Convert Narya (most of the way) over to a Maven Ant task based build. The
ActionScript bits remain belligerent, but the Java stuff is mostly shipshape. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@6222 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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;
|
||||
|
||||
import com.samskivert.util.Logger;
|
||||
|
||||
/**
|
||||
* Contains a reference to the log object used by the Presents services.
|
||||
*/
|
||||
public class Log
|
||||
{
|
||||
/** We dispatch our log messages through this logger. */
|
||||
public static Logger log = Logger.getLogger("com.threerings.presents");
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation indicating that a particular method in a class is safe to be called from any
|
||||
* thread. This is not allowed on a class because it serves purely as documentation to demonstrate
|
||||
* specific situations where methods are intended to be used by both the event dispatch and
|
||||
* blocking threads which are generally uncommon.
|
||||
*/
|
||||
@Target(value=ElementType.METHOD)
|
||||
@Retention(value=RetentionPolicy.SOURCE)
|
||||
public @interface AnyThread
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
/**
|
||||
* An annotation that identifies the invoker on which we do client authentication. This would
|
||||
* generally only be used to bind the auth invoker to a different invoker than the default (which
|
||||
* is the main invoker).
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.PARAMETER })
|
||||
@BindingAnnotation
|
||||
public @interface AuthInvoker
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation indicating that a particular method or all methods in a class (that are not
|
||||
* otherwise explicitly annotated) should only be called while on a servlet or invoker thread
|
||||
* (threads which allow blocking).
|
||||
*
|
||||
* NOTE: These annotations are currently merely advisory, but someday we would like to use AspectJ
|
||||
* or something like that to inject code that enforces these requirements on dev server builds.
|
||||
*/
|
||||
@Target(value={ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(value=RetentionPolicy.SOURCE)
|
||||
public @interface BlockingThread
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import com.samskivert.util.RunQueue;
|
||||
|
||||
/**
|
||||
* An annotation that identifies the distributed object event dispatcher's {@link RunQueue}. Code
|
||||
* that requires the ability to post runnables for execution on the event dispatcher thread can
|
||||
* inject this queue like so:
|
||||
*
|
||||
* <code>@Inject @EventQueue RunQueue _dobjq;</code>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.PARAMETER })
|
||||
@BindingAnnotation
|
||||
public @interface EventQueue
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation indicating that a particular method or all methods in a class (that are not
|
||||
* otherwise explicitly annotated) should only be called while on the distributed object event
|
||||
* dispatch thread.
|
||||
*
|
||||
* NOTE: These annotations are currently merely advisory, but someday we would like to use AspectJ
|
||||
* or something like that to inject code that enforces these requirements on dev server builds.
|
||||
*/
|
||||
@Target(value={ ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(value=RetentionPolicy.SOURCE)
|
||||
public @interface EventThread
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.google.inject.BindingAnnotation;
|
||||
|
||||
import com.samskivert.util.Invoker;
|
||||
|
||||
/**
|
||||
* An annotation that identifies the main Presents {@link Invoker}. Code that requires the ability
|
||||
* to post units for execution on the main invoker thread can inject this queue like so:
|
||||
*
|
||||
* <code>@Inject @MainInvoker Invoker _invoker;</code>
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.FIELD, ElementType.PARAMETER })
|
||||
@BindingAnnotation
|
||||
public @interface MainInvoker
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* An annotation indicating the type of transport desired for a distributed object
|
||||
* class, field, or method.
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface TransportHint
|
||||
{
|
||||
/** The type of transport to use. */
|
||||
Transport.Type type () default Transport.Type.RELIABLE_ORDERED;
|
||||
|
||||
/** For ordered transport types, the channel to use. */
|
||||
int channel () default 0;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.threerings.presents.util.PresentsContext;
|
||||
|
||||
/**
|
||||
* Handles functionality common to nearly all client directors. They generally need to be session
|
||||
* observers so that they can set themselves up when the client logs on (by overriding {@link
|
||||
* #clientDidLogon}) and clean up after themselves when the client logs off (by overriding {@link
|
||||
* #clientDidLogoff}).
|
||||
*/
|
||||
public class BasicDirector
|
||||
implements SessionObserver
|
||||
{
|
||||
/**
|
||||
* Derived directors will need to provide the basic director with a context that it can use to
|
||||
* register itself with the necessary entities.
|
||||
*/
|
||||
protected BasicDirector (PresentsContext ctx)
|
||||
{
|
||||
// save context
|
||||
_ctx = ctx;
|
||||
|
||||
// listen for session start and end
|
||||
Client client = ctx.getClient();
|
||||
client.addClientObserver(this);
|
||||
|
||||
// if we're already logged on, fire off a call to fetch services
|
||||
if (client.isLoggedOn()) {
|
||||
if (isAvailable()) {
|
||||
// this is a sanity check: it will fail if this post-logon initialized director
|
||||
// claims to need service groups (it must make that known prior to logon)
|
||||
registerServices(client);
|
||||
fetchServices(client);
|
||||
}
|
||||
clientObjectUpdated(client);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void clientWillLogon (Client client)
|
||||
{
|
||||
registerServices(client);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void clientDidLogon (Client client)
|
||||
{
|
||||
if (isAvailable()) {
|
||||
fetchServices(client);
|
||||
}
|
||||
clientObjectUpdated(client);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void clientObjectDidChange (Client client)
|
||||
{
|
||||
clientObjectUpdated(client);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void clientDidLogoff (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not this director is available in standalone mode.
|
||||
*/
|
||||
public void setAvailableInStandalone (boolean available)
|
||||
{
|
||||
_availableInStandalone = available;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this director is available in standalone mode (defaults to false).
|
||||
*/
|
||||
public boolean isAvailableInStandalone ()
|
||||
{
|
||||
return _availableInStandalone;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this director is available in the current mode.
|
||||
*/
|
||||
protected boolean isAvailable ()
|
||||
{
|
||||
return isAvailableInStandalone() || !_ctx.getClient().isStandalone();
|
||||
}
|
||||
|
||||
/**
|
||||
* If this director is not currently available, throws a {@link RuntimeException}.
|
||||
*/
|
||||
protected void assertAvailable ()
|
||||
{
|
||||
if (!isAvailable()) {
|
||||
throw new RuntimeException(getClass().getName() +
|
||||
" not available in standalone mode!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in three circumstances: when a director is created and we've already logged on; when
|
||||
* we first log on and when the client object changes after we've already logged on.
|
||||
*/
|
||||
protected void clientObjectUpdated (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* If a director makes use of bootstrap invocation services which are part of a bootstrap
|
||||
* service group, it should register interest in that group here with a call to {@link
|
||||
* Client#addServiceGroup}.
|
||||
*/
|
||||
protected void registerServices (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived directors can override this method and obtain any services they'll need during their
|
||||
* operation via calls to {@link Client#getService}. If the director is available, it will
|
||||
* automatically be called when the client logs on or when the director is constructed if it is
|
||||
* constructed after the client is already logged on.
|
||||
*/
|
||||
protected void fetchServices (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
/** The application context. */
|
||||
protected PresentsContext _ctx;
|
||||
|
||||
/** Whether or not this director is available in standalone mode. */
|
||||
protected boolean _availableInStandalone = true;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* The client adapter makes life easier for client observer classes that
|
||||
* only care about one or two of the client observer callbacks. They can
|
||||
* either extend client adapter or create an anonymous class that extends
|
||||
* it and overrides just the callbacks they care about.
|
||||
*
|
||||
* <p> Note that the client adapter defaults to always ratifying a call to
|
||||
* {@link #clientWillLogoff} by returning true.
|
||||
*/
|
||||
public class ClientAdapter implements ClientObserver
|
||||
{
|
||||
// documentation inherited
|
||||
public void clientWillLogon (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void clientDidLogon (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void clientFailedToLogon (Client client, Exception cause)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void clientObjectDidChange (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void clientConnectionFailed (Client client, Exception cause)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean clientWillLogoff (Client client)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void clientDidLogoff (Client client)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void clientDidClear (Client client)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.nio.channels.SocketChannel;
|
||||
|
||||
import com.samskivert.util.IntListUtil;
|
||||
import com.samskivert.util.Interval;
|
||||
|
||||
import com.samskivert.swing.RuntimeAdjust;
|
||||
|
||||
import com.threerings.presents.data.AuthCodes;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Customizes the blocking communicator with some things that we only do on users' machines (where
|
||||
* there's only one client running, not potentially dozens, and where we're not sending high
|
||||
* volumes of traffic through the client like we do for inter-server communications). This will go
|
||||
* away when we create a special non-blocking communicator for use on the server that integrates
|
||||
* with the ClientManager.
|
||||
*/
|
||||
public class ClientCommunicator extends BlockingCommunicator
|
||||
{
|
||||
public ClientCommunicator (Client client)
|
||||
{
|
||||
super(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets our preferred connection port via our preferences mechanism.
|
||||
*/
|
||||
protected void setPrefPort (String key, int port) {
|
||||
PresentsPrefs.config.setValue(key, port);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets our preferred connection port via our preferences mechanism.
|
||||
*/
|
||||
protected int getPrefPort (String key, int defaultPort) {
|
||||
return PresentsPrefs.config.getValue(key, defaultPort);
|
||||
}
|
||||
|
||||
@Override // from BlockingCommunicator
|
||||
protected void openChannel (InetAddress host)
|
||||
throws IOException
|
||||
{
|
||||
// obtain the list of available ports on which to attempt our client connection and
|
||||
// determine our preferred port
|
||||
String pportKey = _client.getHostname() + ".preferred_port";
|
||||
int[] ports = _client.getPorts();
|
||||
int pport = getPrefPort(pportKey, ports[0]);
|
||||
int ppidx = Math.max(0, IntListUtil.indexOf(ports, pport));
|
||||
|
||||
// try connecting on each of the ports in succession
|
||||
for (int ii = 0; ii < ports.length; ii++) {
|
||||
int port = ports[(ii+ppidx)%ports.length];
|
||||
int nextPort = ports[(ii+ppidx+1)%ports.length];
|
||||
log.info("Connecting", "host", host, "port", port);
|
||||
InetSocketAddress addr = new InetSocketAddress(host, port);
|
||||
try {
|
||||
synchronized (this) {
|
||||
clearPPI(true);
|
||||
_prefPortInterval = new PrefPortInterval(pportKey, port, nextPort);
|
||||
_channel = SocketChannel.open(addr);
|
||||
_prefPortInterval.schedule(PREF_PORT_DELAY);
|
||||
}
|
||||
break;
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (ioe instanceof ConnectException && ii < (ports.length-1)) {
|
||||
_client.reportLogonTribulations(
|
||||
new LogonException(AuthCodes.TRYING_NEXT_PORT, true));
|
||||
continue; // try the next port
|
||||
}
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from BlockingCommunicator
|
||||
protected void readerDidExit ()
|
||||
{
|
||||
// if we haven't recorded a preferred port yet, instead do the failure action since we
|
||||
// didn't stay connected long enough
|
||||
clearPPI(true);
|
||||
super.readerDidExit();
|
||||
}
|
||||
|
||||
@Override // from BlockingCommunicator
|
||||
protected boolean debugLogMessages ()
|
||||
{
|
||||
return _logMessages.getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels our preferred port saving interval. This method is called from the communication
|
||||
* reader thread and the interval thread and must thus be synchronized.
|
||||
*/
|
||||
protected synchronized boolean clearPPI (boolean cancel)
|
||||
{
|
||||
if (_prefPortInterval != null) {
|
||||
if (cancel) {
|
||||
_prefPortInterval.cancel();
|
||||
_prefPortInterval.failed();
|
||||
}
|
||||
_prefPortInterval = null;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Used to save our preferred port once we know our connection is not going to be
|
||||
* unceremoniously closed by Windows Connection Sharing. */
|
||||
protected class PrefPortInterval extends Interval
|
||||
{
|
||||
public PrefPortInterval (String key, int thisPort, int nextPort) {
|
||||
super();
|
||||
_key = key;
|
||||
_thisPort = thisPort;
|
||||
_nextPort = nextPort;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expired () {
|
||||
if (clearPPI(false)) {
|
||||
setPrefPort(_key, _thisPort);
|
||||
}
|
||||
}
|
||||
|
||||
public void failed () {
|
||||
setPrefPort(_key, _nextPort);
|
||||
}
|
||||
|
||||
protected String _key;
|
||||
protected int _thisPort;
|
||||
protected int _nextPort;
|
||||
}
|
||||
|
||||
/** We use this interval to record the preferred port if it stays connected long enough. */
|
||||
protected PrefPortInterval _prefPortInterval;
|
||||
|
||||
/** Used to control low-level message logging. */
|
||||
protected static RuntimeAdjust.BooleanAdjust _logMessages =
|
||||
new RuntimeAdjust.BooleanAdjust("Toggles whether or not all sent and received low-level " +
|
||||
"network events are logged.", "narya.presents.log_events",
|
||||
PresentsPrefs.config, false);
|
||||
|
||||
/** Time a port must remain connected before we mark it as preferred. */
|
||||
protected static long PREF_PORT_DELAY = 5000L;
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import java.awt.event.KeyEvent;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import com.samskivert.util.DebugChords;
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.IntMap;
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.Queue;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.dobj.CompoundEvent;
|
||||
import com.threerings.presents.dobj.DEvent;
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.DObjectManager;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.ObjectDestroyedEvent;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
import com.threerings.presents.net.BootstrapData;
|
||||
import com.threerings.presents.net.BootstrapNotification;
|
||||
import com.threerings.presents.net.EventNotification;
|
||||
import com.threerings.presents.net.FailureResponse;
|
||||
import com.threerings.presents.net.ForwardEventRequest;
|
||||
import com.threerings.presents.net.Message;
|
||||
import com.threerings.presents.net.ObjectResponse;
|
||||
import com.threerings.presents.net.PongResponse;
|
||||
import com.threerings.presents.net.SubscribeRequest;
|
||||
import com.threerings.presents.net.UnsubscribeRequest;
|
||||
import com.threerings.presents.net.UnsubscribeResponse;
|
||||
import com.threerings.presents.net.UpdateThrottleMessage;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* The client distributed object manager manages a set of proxy objects which mirror the
|
||||
* distributed objects maintained on the server. Requests for modifications, etc. are forwarded to
|
||||
* the server and events are dispatched from the server to this client for objects to which this
|
||||
* client is subscribed.
|
||||
*/
|
||||
public class ClientDObjectMgr
|
||||
implements DObjectManager, Runnable
|
||||
{
|
||||
/**
|
||||
* Constructs a client distributed object manager.
|
||||
*
|
||||
* @param comm a communicator instance by which it can communicate with the server.
|
||||
* @param client a reference to the client that is managing this whole communications and event
|
||||
* dispatch business.
|
||||
*/
|
||||
public ClientDObjectMgr (Communicator comm, Client client)
|
||||
{
|
||||
_comm = comm;
|
||||
_client = client;
|
||||
|
||||
// register a debug hook for dumping all objects in the distributed object table
|
||||
DebugChords.registerHook(DUMP_OTABLE_MODMASK, DUMP_OTABLE_KEYCODE, new DebugChords.Hook() {
|
||||
public void invoke () {
|
||||
log.info("Dumping " + _ocache.size() + " objects:");
|
||||
for (DObject obj : _ocache.values()) {
|
||||
log.info(obj.getClass().getName() + " " + obj);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// register a flush interval
|
||||
_flusher = new Interval(client.getRunQueue()) {
|
||||
@Override public void expired () {
|
||||
flushObjects();
|
||||
}
|
||||
};
|
||||
_flusher.schedule(FLUSH_INTERVAL, true);
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public boolean isManager (DObject object)
|
||||
{
|
||||
// we are never authoritative in the present implementation
|
||||
return false;
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public <T extends DObject> void subscribeToObject (int oid, Subscriber<T> target)
|
||||
{
|
||||
if (oid <= 0) {
|
||||
target.requestFailed(oid, new ObjectAccessException("Invalid oid " + oid + "."));
|
||||
} else {
|
||||
queueAction(oid, target, true);
|
||||
}
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public <T extends DObject> void unsubscribeFromObject (int oid, Subscriber<T> target)
|
||||
{
|
||||
queueAction(oid, target, false);
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public void postEvent (DEvent event)
|
||||
{
|
||||
// send a forward event request to the server
|
||||
_comm.postMessage(new ForwardEventRequest(event));
|
||||
}
|
||||
|
||||
// inherit documentation from the interface
|
||||
public void removedLastSubscriber (DObject obj, boolean deathWish)
|
||||
{
|
||||
// if this object has a registered flush delay, don't can it just yet, just slip it onto
|
||||
// the flush queue
|
||||
Class<?> oclass = obj.getClass();
|
||||
for (Class<?> dclass : _delays.keySet()) {
|
||||
if (dclass.isAssignableFrom(oclass)) {
|
||||
long expire = System.currentTimeMillis() + _delays.get(dclass).longValue();
|
||||
_flushes.put(obj.getOid(), new FlushRecord(obj, expire));
|
||||
// Log.info("Flushing " + obj.getOid() + " at " + new java.util.Date(expire));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we didn't find a delay registration, flush immediately
|
||||
flushObject(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an object flush delay.
|
||||
*
|
||||
* @see Client#registerFlushDelay
|
||||
*/
|
||||
public void registerFlushDelay (Class<?> objclass, long delay)
|
||||
{
|
||||
_delays.put(objclass, Long.valueOf(delay));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the communicator when a message arrives from the network layer. We queue it up for
|
||||
* processing and request some processing time on the main thread.
|
||||
*/
|
||||
public void processMessage (Message msg)
|
||||
{
|
||||
if (_client.getRunQueue().isRunning()) {
|
||||
// append it to our queue
|
||||
_actions.append(msg);
|
||||
// and queue ourselves up to be run
|
||||
_client.getRunQueue().postRunnable(this);
|
||||
} else {
|
||||
log.info("Dropping message as RunQueue is shutdown", "msg", msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoked on the main client thread to process any newly arrived messages that we have waiting
|
||||
* in our queue.
|
||||
*/
|
||||
public void run ()
|
||||
{
|
||||
// process the next event on our queue
|
||||
Object obj;
|
||||
if ((obj = _actions.getNonBlocking()) != null) {
|
||||
// do the proper thing depending on the object
|
||||
if (obj instanceof EventNotification) {
|
||||
dispatchEvent(((EventNotification)obj).getEvent());
|
||||
|
||||
} else if (obj instanceof BootstrapNotification) {
|
||||
BootstrapData data = ((BootstrapNotification)obj).getData();
|
||||
_client.gotBootstrap(data, this);
|
||||
|
||||
} else if (obj instanceof ObjectResponse<?>) {
|
||||
registerObjectAndNotify((ObjectResponse<?>)obj);
|
||||
|
||||
} else if (obj instanceof UnsubscribeResponse) {
|
||||
int oid = ((UnsubscribeResponse)obj).getOid();
|
||||
if (_dead.remove(oid) == null) {
|
||||
log.warning("Received unsub ACK from unknown object", "oid", oid);
|
||||
}
|
||||
|
||||
} else if (obj instanceof FailureResponse) {
|
||||
notifyFailure(((FailureResponse)obj).getOid(), ((FailureResponse)obj).getMessage());
|
||||
|
||||
} else if (obj instanceof PongResponse) {
|
||||
_client.gotPong((PongResponse)obj);
|
||||
|
||||
} else if (obj instanceof UpdateThrottleMessage) {
|
||||
UpdateThrottleMessage upmsg = (UpdateThrottleMessage)obj;
|
||||
_client.setOutgoingMessageThrottle(upmsg.messagesPerSec);
|
||||
|
||||
} else if (obj instanceof ObjectAction<?>) {
|
||||
ObjectAction<?> act = (ObjectAction<?>)obj;
|
||||
if (act.subscribe) {
|
||||
doSubscribe(act);
|
||||
} else {
|
||||
doUnsubscribe(act.oid, act.target);
|
||||
}
|
||||
|
||||
} else {
|
||||
log.warning("Unknown action", "action", obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the client is cleaned up due to having disconnected from the server.
|
||||
*/
|
||||
public void cleanup ()
|
||||
{
|
||||
// tell any pending object subscribers that they're not getting their bits
|
||||
for (PendingRequest<?> req : _penders.values()) {
|
||||
for (Subscriber<?> sub : req.targets) {
|
||||
sub.requestFailed(req.oid, new ObjectAccessException("Client connection closed"));
|
||||
}
|
||||
}
|
||||
_penders.clear();
|
||||
_flusher.cancel();
|
||||
}
|
||||
|
||||
protected <T extends DObject> void queueAction (int oid, Subscriber<T> target, boolean subscribe)
|
||||
{
|
||||
if (_client.getRunQueue().isRunning()) {
|
||||
// queue up an action
|
||||
_actions.append(new ObjectAction<T>(oid, target, subscribe));
|
||||
// and queue up the omgr to get invoked on the invoker thread
|
||||
_client.getRunQueue().postRunnable(this);
|
||||
} else {
|
||||
log.info("Dropping subscribe action as RunQueue is stopped",
|
||||
"oid", oid, "subscribe", subscribe);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new event arrives from the server that should be dispatched to subscribers
|
||||
* here on the client.
|
||||
*/
|
||||
protected void dispatchEvent (DEvent event)
|
||||
{
|
||||
// Log.info("Dispatching event: " + evt);
|
||||
|
||||
// look up the object on which we're dispatching this event
|
||||
int remoteOid = event.getTargetOid();
|
||||
DObject target = _ocache.get(remoteOid);
|
||||
if (target == null) {
|
||||
if (!_dead.containsKey(remoteOid)) {
|
||||
log.warning("Unable to dispatch event on non-proxied object " + event + ".");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// because we might be acting as a proxy for a remote server, we may need to fiddle with
|
||||
// this event before we dispatch it
|
||||
_client.convertFromRemote(target, event);
|
||||
|
||||
// if this is a compound event, we need to process its contained events in order
|
||||
if (event instanceof CompoundEvent) {
|
||||
// notify our proxy subscribers in one fell swoop
|
||||
target.notifyProxies(event);
|
||||
|
||||
// now break the event up and dispatch each event to listeners individually
|
||||
List<DEvent> events = ((CompoundEvent)event).getEvents();
|
||||
int ecount = events.size();
|
||||
for (int ii = 0; ii < ecount; ii++) {
|
||||
dispatchEvent(remoteOid, target, events.get(ii));
|
||||
}
|
||||
|
||||
} else {
|
||||
// forward to any proxies (or not if we're dispatching part of a compound event)
|
||||
target.notifyProxies(event);
|
||||
|
||||
// and dispatch the event to regular listeners
|
||||
dispatchEvent(remoteOid, target, event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event on an already resolved target object.
|
||||
*
|
||||
* @param remoteOid is specified explicitly because we will have already translated the event's
|
||||
* target oid into our local object managers oid space if we're acting on behalf of the peer
|
||||
* manager.
|
||||
*/
|
||||
protected void dispatchEvent (int remoteOid, DObject target, DEvent event)
|
||||
{
|
||||
try {
|
||||
// apply the event to the object
|
||||
boolean notify = event.applyToObject(target);
|
||||
|
||||
// if this is an object destroyed event, we need to remove the object from our table
|
||||
if (event instanceof ObjectDestroyedEvent) {
|
||||
// Log.info("Pitching destroyed object [oid=" + remoteOid +
|
||||
// ", class=" + StringUtil.shortClassName(target) + "].");
|
||||
_ocache.remove(remoteOid);
|
||||
}
|
||||
|
||||
// have the object pass this event on to its listeners
|
||||
if (notify) {
|
||||
target.notifyListeners(event);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warning("Failure processing event", "event", event, "target", target, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers this object in our proxy cache and notifies the subscribers that were waiting for
|
||||
* subscription to this object.
|
||||
*/
|
||||
protected <T extends DObject> void registerObjectAndNotify (ObjectResponse<T> orsp)
|
||||
{
|
||||
// let the object know that we'll be managing it
|
||||
T obj = orsp.getObject();
|
||||
obj.setManager(this);
|
||||
|
||||
// stick the object into the proxy object table
|
||||
_ocache.put(obj.getOid(), obj);
|
||||
|
||||
// let the penders know that the object is available
|
||||
PendingRequest<?> req = _penders.remove(obj.getOid());
|
||||
if (req == null) {
|
||||
log.warning("Got object, but no one cares?!", "oid", obj.getOid(), "obj", obj);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int ii = 0; ii < req.targets.size(); ii++) {
|
||||
@SuppressWarnings("unchecked") Subscriber<T> target = (Subscriber<T>)req.targets.get(ii);
|
||||
// add them as a subscriber
|
||||
obj.addSubscriber(target);
|
||||
// and let them know that the object is in
|
||||
target.objectAvailable(obj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the subscribers that had requested this object (for subscription) that it is not
|
||||
* available.
|
||||
*/
|
||||
protected void notifyFailure (int oid, String message)
|
||||
{
|
||||
// let the penders know that the object is not available
|
||||
PendingRequest<?> req = _penders.remove(oid);
|
||||
if (req == null) {
|
||||
log.warning("Failed to get object, but no one cares?!", "oid", oid);
|
||||
return;
|
||||
}
|
||||
|
||||
for (int ii = 0; ii < req.targets.size(); ii++) {
|
||||
req.targets.get(ii).requestFailed(oid, new ObjectAccessException(message));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is guaranteed to be invoked via the invoker and can safely do main thread type things
|
||||
* like call back to the subscriber.
|
||||
*/
|
||||
protected <T extends DObject> void doSubscribe (ObjectAction<T> action)
|
||||
{
|
||||
// Log.info("doSubscribe: " + oid + ": " + target);
|
||||
|
||||
int oid = action.oid;
|
||||
Subscriber<T> target = action.target;
|
||||
|
||||
// first see if we've already got the object in our table
|
||||
@SuppressWarnings("unchecked") T obj = (T)_ocache.get(oid);
|
||||
if (obj != null) {
|
||||
// clear the object out of the flush table if it's in there
|
||||
if (_flushes.remove(oid) != null) {
|
||||
// Log.info("Resurrected " + oid + ".");
|
||||
}
|
||||
// add the subscriber and call them back straight away
|
||||
obj.addSubscriber(target);
|
||||
target.objectAvailable(obj);
|
||||
return;
|
||||
}
|
||||
|
||||
// see if we've already got an outstanding request for this object
|
||||
@SuppressWarnings("unchecked") PendingRequest<T> req = (PendingRequest<T>)_penders.get(oid);
|
||||
if (req != null) {
|
||||
// add this subscriber to the list to be notified when the request is satisfied
|
||||
req.addTarget(target);
|
||||
return;
|
||||
}
|
||||
|
||||
// otherwise we need to create a new request
|
||||
req = new PendingRequest<T>(oid);
|
||||
req.addTarget(target);
|
||||
_penders.put(oid, req);
|
||||
// Log.info("Registering pending request [oid=" + oid + "].");
|
||||
|
||||
// and issue a request to get things rolling
|
||||
_comm.postMessage(new SubscribeRequest(oid));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is guaranteed to be invoked via the invoker and can safely do main thread type things
|
||||
* like call back to the subscriber.
|
||||
*/
|
||||
protected void doUnsubscribe (int oid, Subscriber<?> target)
|
||||
{
|
||||
DObject dobj = _ocache.get(oid);
|
||||
if (dobj != null) {
|
||||
dobj.removeSubscriber(target);
|
||||
|
||||
} else {
|
||||
log.info("Requested to remove subscriber from non-proxied object", "oid", oid,
|
||||
"sub", target);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes a distributed object subscription, issuing an unsubscribe request to the server.
|
||||
*/
|
||||
protected void flushObject (DObject obj)
|
||||
{
|
||||
// move this object into the dead pool so that we don't claim to have it around anymore;
|
||||
// once our unsubscribe message is processed, it'll be 86ed
|
||||
int ooid = obj.getOid();
|
||||
_ocache.remove(ooid);
|
||||
_dead.put(ooid, obj);
|
||||
|
||||
// ship off an unsubscribe message to the server; we'll remove the object from our table
|
||||
// when we get the unsub ack
|
||||
_comm.postMessage(new UnsubscribeRequest(ooid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called periodically to flush any objects that have been lingering due to a previously
|
||||
* enacted flush delay.
|
||||
*/
|
||||
protected void flushObjects ()
|
||||
{
|
||||
long now = System.currentTimeMillis();
|
||||
for (Iterator<IntMap.IntEntry<FlushRecord>> iter = _flushes.intEntrySet().iterator();
|
||||
iter.hasNext(); ) {
|
||||
IntMap.IntEntry<FlushRecord> entry = iter.next();
|
||||
// int oid = entry.getIntKey();
|
||||
FlushRecord rec = entry.getValue();
|
||||
if (rec.expire <= now) {
|
||||
iter.remove();
|
||||
flushObject(rec.object);
|
||||
// Log.info("Flushed object " + oid + ".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The object action is used to queue up a subscribe or unsubscribe request.
|
||||
*/
|
||||
protected static final class ObjectAction<T extends DObject>
|
||||
{
|
||||
public int oid;
|
||||
public Subscriber<T> target;
|
||||
public boolean subscribe;
|
||||
|
||||
public ObjectAction (int oid, Subscriber<T> target, boolean subscribe)
|
||||
{
|
||||
this.oid = oid;
|
||||
this.target = target;
|
||||
this.subscribe = subscribe;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return StringUtil.fieldsToString(this);
|
||||
}
|
||||
}
|
||||
|
||||
/** Represents a pending subscription request. */
|
||||
protected static final class PendingRequest<T extends DObject>
|
||||
{
|
||||
public int oid;
|
||||
public ArrayList<Subscriber<T>> targets = Lists.newArrayList();
|
||||
|
||||
public PendingRequest (int oid)
|
||||
{
|
||||
this.oid = oid;
|
||||
}
|
||||
|
||||
public void addTarget (Subscriber<T> target)
|
||||
{
|
||||
targets.add(target);
|
||||
}
|
||||
}
|
||||
|
||||
/** Used to manage pending object flushes. */
|
||||
protected static final class FlushRecord
|
||||
{
|
||||
/** The object to be flushed. */
|
||||
public DObject object;
|
||||
|
||||
/** The time at which we flush it. */
|
||||
public long expire;
|
||||
|
||||
public FlushRecord (DObject object, long expire)
|
||||
{
|
||||
this.object = object;
|
||||
this.expire = expire;
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to the communicator that sends and receives messages for this client. */
|
||||
protected Communicator _comm;
|
||||
|
||||
/** A reference to our client instance. */
|
||||
protected Client _client;
|
||||
|
||||
/** Periodically calls {@link #flushObject}. */
|
||||
protected Interval _flusher;
|
||||
|
||||
/** Our primary dispatch queue. */
|
||||
protected Queue<Object> _actions = new Queue<Object>();
|
||||
|
||||
/** All of the distributed objects that are active on this client. */
|
||||
protected HashIntMap<DObject> _ocache = new HashIntMap<DObject>();
|
||||
|
||||
/** Objects that have been marked for death. */
|
||||
protected HashIntMap<DObject> _dead = new HashIntMap<DObject>();
|
||||
|
||||
/** Pending object subscriptions. */
|
||||
protected HashIntMap<PendingRequest<?>> _penders = new HashIntMap<PendingRequest<?>>();
|
||||
|
||||
/** A mapping from distributed object class to flush delay. */
|
||||
protected HashMap<Class<?>, Long> _delays = Maps.newHashMap();
|
||||
|
||||
/** A set of objects waiting to be flushed. */
|
||||
protected HashIntMap<FlushRecord> _flushes = new HashIntMap<FlushRecord>();
|
||||
|
||||
/** The modifiers for our dump table debug hook (Alt+Shift). */
|
||||
protected static int DUMP_OTABLE_MODMASK = KeyEvent.ALT_DOWN_MASK|KeyEvent.SHIFT_DOWN_MASK;
|
||||
|
||||
/** The key code for our dump table debug hook (o). */
|
||||
protected static int DUMP_OTABLE_KEYCODE = KeyEvent.VK_O;
|
||||
|
||||
/** Flush expired objects every 30 seconds. */
|
||||
protected static final long FLUSH_INTERVAL = 30 * 1000L;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* A client observer is a more detailed version of the {@link SessionObserver} for entities that
|
||||
* are interested in more detail about the logon/logoff process.
|
||||
*
|
||||
* <p> In the normal course of affairs, {@link SessionObserver#clientDidLogon} will be called after
|
||||
* the client successfully logs on to the server and {@link SessionObserver#clientDidLogoff} will
|
||||
* be called after the client logs off of the server. If logon fails for any reason,
|
||||
* {@link #clientFailedToLogon} will be called to explain the failure.
|
||||
*
|
||||
* <p> {@link #clientWillLogoff} will only be called when an abortable logoff is requested (like
|
||||
* when the user clicks on a logoff button of some sort). It will not be called during
|
||||
* non-abortable logoff requests (like when the browser calls stop on the applet and is about to
|
||||
* yank the rug out from under us). If an observer aborts the logoff request, it should notify the
|
||||
* user in some way why the request was aborted (<em>but it shouldn't do so on the thread that
|
||||
* calls {@link #clientWillLogoff}</em>).
|
||||
*
|
||||
* <p> If the client connection fails unexpectedly, {@link #clientConnectionFailed} will be called
|
||||
* to let the observers know that we lost our connection to the server.
|
||||
* {@link SessionObserver#clientDidLogoff} will be called immediately afterwards as a normal logoff
|
||||
* procedure is effected.
|
||||
*/
|
||||
public interface ClientObserver extends SessionObserver
|
||||
{
|
||||
/**
|
||||
* Called if anything fails during the logon attempt. This could be a network failure,
|
||||
* authentication failure or otherwise. The exception provided will indicate the cause of the
|
||||
* failure.
|
||||
*
|
||||
* @param cause an exception indicating the cause of the logon failure. <em>Note:</em> this
|
||||
* may be a {@link LogonException} and if so, the caller <em>must</em> check {@link
|
||||
* LogonException#isStillInProgress} to find out if the logon process has totally failed or if
|
||||
* we are simply reporting intermediate status (we might be falling back to an alternative port
|
||||
* or delaying our auto-retry attempt due to server overload).
|
||||
*/
|
||||
void clientFailedToLogon (Client client, Exception cause);
|
||||
|
||||
/**
|
||||
* Called when the connection to the server went away for some unexpected reason. This will be
|
||||
* followed by a call to {@link SessionObserver#clientDidLogoff}.
|
||||
*/
|
||||
void clientConnectionFailed (Client client, Exception cause);
|
||||
|
||||
/**
|
||||
* Called when an abortable logoff request is made. If the observer returns false from this
|
||||
* method, the client will abort the logoff request.
|
||||
*/
|
||||
boolean clientWillLogoff (Client client);
|
||||
|
||||
/**
|
||||
* Called after the client is completely logged off from a successful session and is ready to
|
||||
* reconnect to a new server if desired. This will only be called after an active session was
|
||||
* terminated, not after a logon attempt failed as that failure will be reported by {@link
|
||||
* #clientFailedToLogon}.
|
||||
*/
|
||||
void clientDidClear (Client client);
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.samskivert.util.RunAnywhere;
|
||||
|
||||
import com.threerings.presents.net.AuthResponse;
|
||||
import com.threerings.presents.net.AuthResponseData;
|
||||
import com.threerings.presents.net.Message;
|
||||
import com.threerings.presents.net.UpstreamMessage;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Handles sending and receiving messages for the client.
|
||||
*/
|
||||
public abstract class Communicator
|
||||
{
|
||||
/**
|
||||
* Creates a new communicator instance which is associated with the supplied client.
|
||||
*/
|
||||
public Communicator (Client client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs on to the server and initiates our full-duplex message exchange.
|
||||
*/
|
||||
public abstract void logon ();
|
||||
|
||||
/**
|
||||
* Delivers a logoff notification to the server and shuts down the network connection. Also
|
||||
* causes all communication threads to terminate.
|
||||
*/
|
||||
public abstract void logoff ();
|
||||
|
||||
/**
|
||||
* Notifies the communicator that the client has received its bootstrap data.
|
||||
*/
|
||||
public abstract void gotBootstrap ();
|
||||
|
||||
/**
|
||||
* Queues up the specified message for delivery upstream.
|
||||
*/
|
||||
public abstract void postMessage (UpstreamMessage msg);
|
||||
|
||||
/**
|
||||
* Configures this communicator with a custom class loader to be used when reading and writing
|
||||
* objects over the network.
|
||||
*/
|
||||
public abstract void setClassLoader (ClassLoader loader);
|
||||
|
||||
/**
|
||||
* Returns the time at which we last sent a packet to the server.
|
||||
*/
|
||||
public long getLastWrite ()
|
||||
{
|
||||
return _lastWrite;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether we should transmit datagrams.
|
||||
*/
|
||||
public boolean getTransmitDatagrams ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a note of the time at which we last communicated with the server.
|
||||
*/
|
||||
protected synchronized void updateWriteStamp ()
|
||||
{
|
||||
_lastWrite = RunAnywhere.currentTimeMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must call this method when they receive the authentication response.
|
||||
*/
|
||||
protected void gotAuthResponse (AuthResponse rsp)
|
||||
throws LogonException
|
||||
{
|
||||
AuthResponseData data = rsp.getData();
|
||||
if (!data.code.equals(AuthResponseData.SUCCESS)) {
|
||||
throw new LogonException(data.code);
|
||||
}
|
||||
logonSucceeded(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the authentication process completes successfully. Derived classes can override
|
||||
* this method and complete any initialization that need wait for authentication success.
|
||||
*/
|
||||
protected synchronized void logonSucceeded (AuthResponseData data)
|
||||
{
|
||||
// create our distributed object manager
|
||||
_omgr = new ClientDObjectMgr(this, _client);
|
||||
|
||||
// fill the auth data into the client's local field so that it can be requested by external
|
||||
// entities
|
||||
_client._authData = data;
|
||||
|
||||
// wait for the bootstrap notification before we claim that we're actually logged on
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback called by the reader thread when it has parsed a new message from the socket and
|
||||
* wishes to have it processed.
|
||||
*/
|
||||
protected void processMessage (Message msg)
|
||||
{
|
||||
// post this message to the dobjmgr queue
|
||||
_omgr.processMessage(msg);
|
||||
}
|
||||
|
||||
protected void notifyClientObservers (ObserverOps.Session op)
|
||||
{
|
||||
if (_client != null) {
|
||||
_client.notifyObservers(op);
|
||||
} else {
|
||||
log.warning("Dropping client observer notification.", "op", op);
|
||||
}
|
||||
}
|
||||
|
||||
protected void clientCleanup (Exception logonError)
|
||||
{
|
||||
if (_client != null) {
|
||||
_client.cleanup(logonError);
|
||||
_client = null; // prevent any post-cleanup tomfoolery
|
||||
}
|
||||
}
|
||||
|
||||
protected Client _client;
|
||||
protected ClientDObjectMgr _omgr;
|
||||
protected long _lastWrite;
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.threerings.presents.net.PingRequest;
|
||||
import com.threerings.presents.net.PongResponse;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Used to compute the client/server time delta, attempting to account for
|
||||
* the network delay experienced when the server sends its current time to
|
||||
* the client.
|
||||
*/
|
||||
public class DeltaCalculator
|
||||
{
|
||||
/**
|
||||
* Constructs a delta calculator which is used to calculate the time
|
||||
* delta between the client and server, accounting reasonably well for
|
||||
* the delay introduced by sending a timestamp over the network from
|
||||
* the server to the client.
|
||||
*/
|
||||
public DeltaCalculator ()
|
||||
{
|
||||
_deltas = new long[CLOCK_SYNC_PING_COUNT];
|
||||
}
|
||||
|
||||
/**
|
||||
* Should we send another ping?
|
||||
*/
|
||||
public boolean shouldSendPing ()
|
||||
{
|
||||
return (_ping == null) && !isDone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called when a ping message is sent to the server.
|
||||
*/
|
||||
public void sentPing (PingRequest ping)
|
||||
{
|
||||
_ping = ping;
|
||||
}
|
||||
|
||||
/**
|
||||
* Must be called when the pong response arrives back from the server.
|
||||
*
|
||||
* @return true if we've iterated sufficiently many times to establish
|
||||
* a stable time delta estimate.
|
||||
*/
|
||||
public boolean gotPong (PongResponse pong)
|
||||
{
|
||||
if (_ping == null) {
|
||||
// an errant pong that is likely being processed late after
|
||||
// a new connection was opened.
|
||||
return false;
|
||||
}
|
||||
// don't freak out if they keep calling gotPong() after we're done
|
||||
if (_iter >= _deltas.length) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// make a note of when the ping message was sent and when the pong
|
||||
// response was received (both in client time)
|
||||
long send = _ping.getPackStamp(), recv = pong.getUnpackStamp();
|
||||
_ping = null; // clear out the saved sent ping
|
||||
|
||||
// make a note of when the pong response was sent (in server time)
|
||||
// and the processing delay incurred on the server
|
||||
long server = pong.getPackStamp(), delay = pong.getProcessDelay();
|
||||
|
||||
// compute the network delay (round-trip time divided by two)
|
||||
long nettime = (recv - send - delay)/2;
|
||||
|
||||
// the time delta is the client time when the pong was received
|
||||
// minus the server's send time (plus network delay): dT = C - S
|
||||
_deltas[_iter] = recv - (server + nettime);
|
||||
|
||||
log.debug("Calculated delta", "delay", delay, "nettime", nettime, "delta", _deltas[_iter],
|
||||
"rtt", (recv-send));
|
||||
|
||||
return (++_iter >= CLOCK_SYNC_PING_COUNT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the best estimate client/server time-delta.
|
||||
*/
|
||||
public long getTimeDelta ()
|
||||
{
|
||||
if (_iter == 0) { // no responses yet
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// Return a median value as our estimate, rather than an average.
|
||||
// Mdb writes:
|
||||
// -----------
|
||||
// I used the median because that was more likely to result in a
|
||||
// sensible value.
|
||||
//
|
||||
// Assuming there are two kinds of packets, one that goes and comes
|
||||
// back without delay and provides an accurate time value, and one
|
||||
// that gets delayed somewhere on the way there or the way back and
|
||||
// provides an inaccurate time value.
|
||||
//
|
||||
// If no packets are delayed, both algorithms should be fine. If one
|
||||
// packet is delayed the median will select the middle, non-delayed
|
||||
// packet, whereas the average will skew everything a bit because
|
||||
// of the delayed packet. If two packets are delayed, the median
|
||||
// will be more skewed than the average because it will benefit
|
||||
// from the one accurate packet and if all three packets are delayed
|
||||
// both algorithms will be (approximately) equally inaccurate.
|
||||
//
|
||||
// I believe the chances are most likely that zero or one packets
|
||||
// will be delayed, so I chose the median rather than the average.
|
||||
// -----------
|
||||
|
||||
// copy the deltas array so that we don't alter things before
|
||||
// all pongs have arrived
|
||||
long[] deltasCopy = new long[_iter];
|
||||
System.arraycopy(_deltas, 0, deltasCopy, 0, _iter);
|
||||
|
||||
// sort the estimates and return one from the middle
|
||||
Arrays.sort(deltasCopy);
|
||||
return deltasCopy[deltasCopy.length/2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this calculator has enough data to compute a time
|
||||
* delta estimate. Stick a fork in it!
|
||||
*/
|
||||
public boolean isDone ()
|
||||
{
|
||||
return (_iter >= CLOCK_SYNC_PING_COUNT);
|
||||
}
|
||||
|
||||
/** The number of ping/pong iterations we've made. */
|
||||
protected int _iter;
|
||||
|
||||
/** Client/server time delta estimates. */
|
||||
protected long[] _deltas;
|
||||
|
||||
/** A reference to the most recently sent ping which we use to obtain
|
||||
* the appropriate send stamp when we get the corresponding receive
|
||||
* stamp. */
|
||||
protected PingRequest _ping;
|
||||
|
||||
/** The number of times we PING during clock sync to try to smooth out
|
||||
* network jiggling. */
|
||||
protected static final int CLOCK_SYNC_PING_COUNT = 3;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Provides the basic functionality used to dispatch invocation notification events.
|
||||
*/
|
||||
public abstract class InvocationDecoder
|
||||
{
|
||||
/** The receiver for which we're decoding and dispatching notifications. */
|
||||
public InvocationReceiver receiver;
|
||||
|
||||
/**
|
||||
* Returns the generated hash code that is used to identify this invocation notification
|
||||
* service.
|
||||
*/
|
||||
public abstract String getReceiverCode ();
|
||||
|
||||
/**
|
||||
* Dispatches the specified method to our receiver.
|
||||
*/
|
||||
public void dispatchNotification (int methodId, Object[] args)
|
||||
{
|
||||
log.warning("Requested to dispatch unknown method", "receiver", receiver,
|
||||
"methodId", methodId, "args", args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
|
||||
import com.threerings.presents.client.InvocationReceiver.Registration;
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
import com.threerings.presents.data.InvocationMarshaller.ListenerMarshaller;
|
||||
import com.threerings.presents.dobj.DEvent;
|
||||
import com.threerings.presents.dobj.DObjectManager;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.presents.dobj.EventListener;
|
||||
import com.threerings.presents.dobj.InvocationNotificationEvent;
|
||||
import com.threerings.presents.dobj.InvocationRequestEvent;
|
||||
import com.threerings.presents.dobj.InvocationResponseEvent;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
import com.threerings.presents.dobj.ObjectAccessException;
|
||||
import com.threerings.presents.dobj.Subscriber;
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Handles the client side management of the invocation services.
|
||||
*/
|
||||
public class InvocationDirector
|
||||
implements EventListener
|
||||
{
|
||||
/**
|
||||
* Initializes the invocation director. This is called when the client establishes a connection
|
||||
* with the server.
|
||||
*
|
||||
* @param omgr the distributed object manager via which the invocation manager will send and
|
||||
* receive events.
|
||||
* @param cloid the oid of the object on which invocation notifications as well as invocation
|
||||
* responses will be received.
|
||||
* @param client a reference to the client for whom we're doing our business.
|
||||
*/
|
||||
public void init (DObjectManager omgr, final int cloid, Client client)
|
||||
{
|
||||
// sanity check
|
||||
if (_clobj != null) {
|
||||
log.warning("Zoiks, client object around during invmgr init!");
|
||||
cleanup();
|
||||
}
|
||||
|
||||
// keep these for later
|
||||
_omgr = omgr;
|
||||
_client = client;
|
||||
|
||||
// add ourselves as a subscriber to the client object
|
||||
_omgr.subscribeToObject(cloid, new Subscriber<ClientObject>() {
|
||||
public void objectAvailable (ClientObject clobj) {
|
||||
// add ourselves as an event listener
|
||||
clobj.addListener(InvocationDirector.this);
|
||||
|
||||
// clear out our previous registrations
|
||||
clobj.setReceivers(new DSet<Registration>());
|
||||
|
||||
// keep a handle on this bad boy
|
||||
_clobj = clobj;
|
||||
|
||||
// assign a mapping to already registered receivers
|
||||
assignReceiverIds();
|
||||
|
||||
// let the client know that we're ready to go now that we've got our subscription
|
||||
// to the client object
|
||||
_client.gotClientObject(_clobj);
|
||||
}
|
||||
|
||||
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||
// aiya! we were unable to subscribe to the client object. we're hosed!
|
||||
log.warning("Invocation director unable to subscribe to client object",
|
||||
"cloid", cloid, "cause", cause + "]!");
|
||||
_client.getClientObjectFailed(cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out our session information. This is called when the client ends its session with the
|
||||
* server.
|
||||
*/
|
||||
public void cleanup ()
|
||||
{
|
||||
// wipe our client object, receiver mappings and listener mappings
|
||||
_clobj = null;
|
||||
_receivers.clear();
|
||||
_listeners.clear();
|
||||
|
||||
// also reset our counters
|
||||
_requestId = 0;
|
||||
_receiverId = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an invocation notification receiver by way of its notification event decoder.
|
||||
*/
|
||||
public void registerReceiver (InvocationDecoder decoder)
|
||||
{
|
||||
// add the receiver to the list
|
||||
_reclist.add(decoder);
|
||||
|
||||
// if we're already online, assign a receiver id to this decoder
|
||||
if (_clobj != null) {
|
||||
assignReceiverId(decoder);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a receiver registration.
|
||||
*/
|
||||
public void unregisterReceiver (String receiverCode)
|
||||
{
|
||||
// remove the receiver from the list
|
||||
for (Iterator<InvocationDecoder> iter = _reclist.iterator(); iter.hasNext(); ) {
|
||||
InvocationDecoder decoder = iter.next();
|
||||
if (decoder.getReceiverCode().equals(receiverCode)) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// if we're logged on, clear out any receiver id mapping
|
||||
if (_clobj != null) {
|
||||
Registration rreg = _clobj.receivers.get(receiverCode);
|
||||
if (rreg == null) {
|
||||
log.warning("Receiver unregistered for which we have no id to code mapping",
|
||||
"code", receiverCode);
|
||||
} else {
|
||||
_receivers.remove(rreg.receiverId);
|
||||
// Log.info("Cleared receiver " + StringUtil.shortClassName(decoder) +
|
||||
// " " + rreg + ".");
|
||||
}
|
||||
_clobj.removeFromReceivers(receiverCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns a receiver id to this decoder and publishes it in the {@link ClientObject#receivers}
|
||||
* field.
|
||||
*/
|
||||
protected void assignReceiverId (InvocationDecoder decoder)
|
||||
{
|
||||
Registration reg = new Registration(decoder.getReceiverCode(), nextReceiverId());
|
||||
// stick the mapping into the client object
|
||||
_clobj.addToReceivers(reg);
|
||||
// and map the receiver in our receivers table
|
||||
_receivers.put(reg.receiverId, decoder);
|
||||
// Log.info("Registered receiver " + StringUtil.shortClassName(decoder) + " " + reg + ".");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when we log on; generates mappings for all receivers registered prior to logon.
|
||||
*/
|
||||
protected void assignReceiverIds ()
|
||||
{
|
||||
// pack all the set add events into a single transaction
|
||||
_clobj.startTransaction();
|
||||
try {
|
||||
for (InvocationDecoder decoder : _reclist) {
|
||||
assignReceiverId(decoder);
|
||||
}
|
||||
} finally {
|
||||
_clobj.commitTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified invocation request be packaged up and sent to the supplied
|
||||
* invocation oid.
|
||||
*/
|
||||
public void sendRequest (int invOid, int invCode, int methodId, Object[] args)
|
||||
{
|
||||
sendRequest(invOid, invCode, methodId, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified invocation request be packaged up and sent to the supplied
|
||||
* invocation oid.
|
||||
*/
|
||||
public void sendRequest (
|
||||
int invOid, int invCode, int methodId, Object[] args, Transport transport)
|
||||
{
|
||||
if (_clobj == null) {
|
||||
log.warning("Dropping invocation request on shutdown director", "code", invCode,
|
||||
"methodId", methodId);
|
||||
return;
|
||||
}
|
||||
|
||||
// configure any invocation listener marshallers among the arguments
|
||||
int acount = args.length;
|
||||
for (int ii = 0; ii < acount; ii++) {
|
||||
Object arg = args[ii];
|
||||
if (arg instanceof ListenerMarshaller) {
|
||||
ListenerMarshaller lm = (ListenerMarshaller)arg;
|
||||
lm.requestId = nextRequestId();
|
||||
lm.mapStamp = System.currentTimeMillis();
|
||||
// create a mapping for this marshaller so that we can properly dispatch responses
|
||||
// sent to it
|
||||
_listeners.put(lm.requestId, lm);
|
||||
}
|
||||
}
|
||||
|
||||
// create an invocation request event
|
||||
InvocationRequestEvent event =
|
||||
new InvocationRequestEvent(invOid, invCode, methodId, args, transport);
|
||||
|
||||
// because invocation directors are used on the server, we set the source oid here so that
|
||||
// invocation requests are properly attributed to the right client object when created by
|
||||
// server-side entities only sort of pretending to be a client
|
||||
event.setSourceOid(_clobj.getOid());
|
||||
|
||||
// Log.info("Sending invreq " + event + ".");
|
||||
|
||||
// now dispatch the event
|
||||
_omgr.postEvent(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process notification and response events arriving on user object.
|
||||
*/
|
||||
public void eventReceived (DEvent event)
|
||||
{
|
||||
if (event instanceof InvocationResponseEvent) {
|
||||
InvocationResponseEvent ire = (InvocationResponseEvent)event;
|
||||
handleInvocationResponse(ire.getRequestId(), ire.getMethodId(), ire.getArgs());
|
||||
|
||||
} else if (event instanceof InvocationNotificationEvent) {
|
||||
InvocationNotificationEvent ine = (InvocationNotificationEvent)event;
|
||||
handleInvocationNotification(ine.getReceiverId(), ine.getMethodId(), ine.getArgs());
|
||||
|
||||
} else if (event instanceof MessageEvent) {
|
||||
MessageEvent mevt = (MessageEvent)event;
|
||||
if (mevt.getName().equals(ClientObject.CLOBJ_CHANGED)) {
|
||||
handleClientObjectChanged(((Integer)mevt.getArgs()[0]).intValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an invocation response.
|
||||
*/
|
||||
protected void handleInvocationResponse (int reqId, int methodId, Object[] args)
|
||||
{
|
||||
// look up the invocation marshaller registered for that response
|
||||
ListenerMarshaller listener = _listeners.remove(reqId);
|
||||
if (listener == null) {
|
||||
log.warning("Received invocation response for which we have no registered listener. " +
|
||||
"It is possible that this listener was flushed because the response did " +
|
||||
"not arrive within " + LISTENER_MAX_AGE + " milliseconds.",
|
||||
"reqId", reqId, "methId", methodId, "args", args);
|
||||
return;
|
||||
}
|
||||
|
||||
// log.info("Dispatching invocation response", "listener", listener,
|
||||
// "methId", methodId, "args", args);
|
||||
|
||||
// dispatch the response
|
||||
try {
|
||||
listener.dispatchResponse(methodId, args);
|
||||
} catch (Throwable t) {
|
||||
log.warning("Invocation response listener choked", "listener", listener,
|
||||
"methId", methodId, "args", args, t);
|
||||
}
|
||||
|
||||
// flush expired listeners periodically
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - _lastFlushTime > LISTENER_FLUSH_INTERVAL) {
|
||||
_lastFlushTime = now;
|
||||
flushListeners(now);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an invocation notification.
|
||||
*/
|
||||
protected void handleInvocationNotification (int receiverId, int methodId, Object[] args)
|
||||
{
|
||||
// look up the decoder registered for this receiver
|
||||
InvocationDecoder decoder = _receivers.get(receiverId);
|
||||
if (decoder == null) {
|
||||
log.warning("Received notification for which we have no registered receiver",
|
||||
"recvId", receiverId, "methodId", methodId, "args", args);
|
||||
return;
|
||||
}
|
||||
|
||||
// log.info("Dispatching invocation notification", "receiver", decoder.receiver,
|
||||
// "methodId", methodId, "args", args);
|
||||
|
||||
try {
|
||||
decoder.dispatchNotification(methodId, args);
|
||||
} catch (Throwable t) {
|
||||
log.warning("Invocation notification receiver choked", "receiver", decoder.receiver,
|
||||
"methId", methodId, "args", args, t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server has informed us that our previous client object is going the way of
|
||||
* the Dodo because we're changing screen names. We subscribe to the new object and report to
|
||||
* the client once we've got our hands on it.
|
||||
*/
|
||||
protected void handleClientObjectChanged (int newCloid)
|
||||
{
|
||||
// subscribe to the new client object
|
||||
_omgr.subscribeToObject(newCloid, new Subscriber<ClientObject>() {
|
||||
public void objectAvailable (ClientObject clobj) {
|
||||
// grab a reference to our old receiver registrations
|
||||
DSet<Registration> receivers = _clobj.receivers;
|
||||
|
||||
// replace the client object
|
||||
_clobj = clobj;
|
||||
|
||||
// add ourselves as an event listener
|
||||
_clobj.addListener(InvocationDirector.this);
|
||||
|
||||
// reregister our receivers
|
||||
_clobj.startTransaction();
|
||||
try {
|
||||
_clobj.setReceivers(new DSet<Registration>());
|
||||
for (Registration reg : receivers) {
|
||||
_clobj.addToReceivers(reg);
|
||||
}
|
||||
} finally {
|
||||
_clobj.commitTransaction();
|
||||
}
|
||||
|
||||
// and report the switcheroo back to the client
|
||||
_client.clientObjectDidChange(_clobj);
|
||||
}
|
||||
|
||||
public void requestFailed (int oid, ObjectAccessException cause) {
|
||||
log.warning("Aiya! Unable to subscribe to changed client object", "cloid", oid,
|
||||
"cause", cause);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes listener mappings that are older than {@link #LISTENER_MAX_AGE} milliseconds. An
|
||||
* alternative to flushing listeners that did not explicitly receive a response within our
|
||||
* expiry time period is to have the server's proxy listener send a message to the client when
|
||||
* it is finalized. We then know that no server entity will subsequently use that proxy
|
||||
* listener to send a response to the client. This involves more network traffic and complexity
|
||||
* than seems necessary and if a user of the system does respond after their listener has been
|
||||
* flushed, an informative warning will be logged. (Famous last words.)
|
||||
*/
|
||||
protected void flushListeners (long now)
|
||||
{
|
||||
if (_listeners.size() > 0) {
|
||||
long then = now - LISTENER_MAX_AGE;
|
||||
Iterator<ListenerMarshaller> iter = _listeners.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
ListenerMarshaller lm = iter.next();
|
||||
if (then > lm.mapStamp) {
|
||||
// Log.info("Flushing marshaller " + lm + ".");
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to generate monotonically increasing invocation request ids.
|
||||
*/
|
||||
protected synchronized short nextRequestId ()
|
||||
{
|
||||
return _requestId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to generate monotonically increasing invocation receiver ids.
|
||||
*/
|
||||
protected synchronized short nextReceiverId ()
|
||||
{
|
||||
return _receiverId++;
|
||||
}
|
||||
|
||||
/** The distributed object manager with which we interact. */
|
||||
protected DObjectManager _omgr;
|
||||
|
||||
/** The client for whom we're working. */
|
||||
protected Client _client;
|
||||
|
||||
/** Our client object; invocation responses and notifications are received on this object. */
|
||||
protected ClientObject _clobj;
|
||||
|
||||
/** Used to generate monotonically increasing request ids. */
|
||||
protected short _requestId;
|
||||
|
||||
/** Used to generate monotonically increasing receiver ids. */
|
||||
protected short _receiverId;
|
||||
|
||||
/** Used to keep track of invocation service listeners which will receive responses from
|
||||
* invocation service requests. */
|
||||
protected HashIntMap<ListenerMarshaller> _listeners = new HashIntMap<ListenerMarshaller>();
|
||||
|
||||
/** Used to keep track of invocation notification receivers. */
|
||||
protected HashIntMap<InvocationDecoder> _receivers = new HashIntMap<InvocationDecoder>();
|
||||
|
||||
/** All registered receivers are maintained in a list so that we can assign receiver ids to
|
||||
* them when we go online. */
|
||||
protected ArrayList<InvocationDecoder> _reclist = Lists.newArrayList();
|
||||
|
||||
/** The last time we flushed our listeners. */
|
||||
protected long _lastFlushTime;
|
||||
|
||||
/** The minimum interval between listener flush attempts. */
|
||||
protected static final long LISTENER_FLUSH_INTERVAL = 15000L;
|
||||
|
||||
/** Listener mappings older than 90 seconds are reaped. */
|
||||
protected static final long LISTENER_MAX_AGE = 90 * 1000L;
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
/**
|
||||
* Invocation notification receipt interfaces should be defined as
|
||||
* extending this interface. Actual notification receivers will implement
|
||||
* the requisite receiver interface definition and register themselves
|
||||
* with the {@link InvocationDirector} using the generated {@link
|
||||
* InvocationDecoder} class specific to the notification receiver
|
||||
* interface in question. For example:
|
||||
*
|
||||
* <pre>
|
||||
* public class FooDirector implements FooReceiver
|
||||
* {
|
||||
* public FooDirector (PresentsContext ctx)
|
||||
* {
|
||||
* InvocationDirector idir = ctx.getClient().getInvocationDirector();
|
||||
* idir.registerReceiver(new FooDecoder(this));
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @see InvocationDirector#registerReceiver
|
||||
*/
|
||||
public interface InvocationReceiver
|
||||
{
|
||||
/**
|
||||
* Used to maintain a registry of invocation receivers that can be
|
||||
* used to convert (large) hash codes into (small) registration
|
||||
* numbers.
|
||||
*/
|
||||
public static class Registration implements DSet.Entry
|
||||
{
|
||||
/** The unique hash code associated with this invocation receiver
|
||||
* class. */
|
||||
public String receiverCode;
|
||||
|
||||
/** The unique id assigned to this invocation receiver class at
|
||||
* registration time. */
|
||||
public short receiverId;
|
||||
|
||||
/** Creates and initializes a registration instance. */
|
||||
public Registration (String receiverCode, short receiverId)
|
||||
{
|
||||
this.receiverCode = receiverCode;
|
||||
this.receiverId = receiverId;
|
||||
}
|
||||
|
||||
/** Creates a blank instance suitable for unserialization. */
|
||||
public Registration ()
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public Comparable<?> getKey ()
|
||||
{
|
||||
return receiverCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[" + receiverCode + " => " + receiverId + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* Serves as the base interface for invocation services. An invocation service can be defined by
|
||||
* extending this interface and defining service methods, as well as response listeners (which must
|
||||
* extend {@link InvocationListener}). For example:
|
||||
*
|
||||
* <pre>
|
||||
* public interface LocationService extends InvocationService
|
||||
* {
|
||||
*
|
||||
* // Used to communicate responses to moveTo() requests.
|
||||
* public interface MoveListener extends InvocationListener
|
||||
* {
|
||||
* // Called in response to a successful moveTo() request.
|
||||
* void moveSucceeded (PlaceConfig config);
|
||||
* }
|
||||
*
|
||||
* // Requests that this client's body be moved to the specified location.
|
||||
* //
|
||||
* // @param placeId the object id of the place object to which the body should be moved.
|
||||
* // @param listener the listener that will be informed of success or failure.
|
||||
* void moveTo (int placeId, MoveListener listener);
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* From this interface, a <code>LocationProvider</code> interface will be generated which should be
|
||||
* implemented by whatever server entity that will actually provide the server side of this
|
||||
* invocation service. That provider interface would look like the following:
|
||||
*
|
||||
* <pre>
|
||||
* public interface LocationProvider extends InvocationProvider
|
||||
* {
|
||||
* // Requests that this client's body be moved to the specified location.
|
||||
* //
|
||||
* // @param caller the client object of the client that invoked this remotely callable method.
|
||||
* // @param placeId the object id of the place object to which the body should be moved.
|
||||
* // @param listener the listener that should be informed of success or failure.
|
||||
* void moveTo (ClientObject caller, int placeId, MoveListener listener)
|
||||
* throws InvocationException;
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public interface InvocationService
|
||||
{
|
||||
/**
|
||||
* Invocation service methods that require a response should take a listener argument that can
|
||||
* be notified of request success or failure. The listener argument should extend this
|
||||
* interface so that generic failure can be reported in all cases. For example:
|
||||
*
|
||||
* <pre>
|
||||
* // Used to communicate responses to <code>moveTo</code> requests.
|
||||
* public interface MoveListener extends InvocationListener
|
||||
* {
|
||||
* // Called in response to a successful <code>moveTo</code> request.
|
||||
* void moveSucceeded (PlaceConfig config);
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
public static interface InvocationListener
|
||||
{
|
||||
/**
|
||||
* Called to report request failure. If the invocation services system detects failure of
|
||||
* any kind, it will report it via this callback. Particular services may also make use of
|
||||
* this callback to report failures of their own, or they may opt to define more specific
|
||||
* failure callbacks.
|
||||
*/
|
||||
void requestFailed (String cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the {@link InvocationListener} with a basic success callback.
|
||||
*/
|
||||
public static interface ConfirmListener extends InvocationListener
|
||||
{
|
||||
/**
|
||||
* Indicates that the request was successfully processed.
|
||||
*/
|
||||
void requestProcessed ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the {@link InvocationListener} with a basic success callback that delivers a result
|
||||
* object.
|
||||
*/
|
||||
public static interface ResultListener extends InvocationListener
|
||||
{
|
||||
/**
|
||||
* Indicates that the request was successfully processed.
|
||||
*/
|
||||
void requestProcessed (Object result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.samskivert.util.Logger;
|
||||
|
||||
/**
|
||||
* Implements the basic {@link InvocationService.InvocationListener} and logs the failure.
|
||||
*/
|
||||
public class LoggingListener
|
||||
implements InvocationService.InvocationListener
|
||||
{
|
||||
/**
|
||||
* Constructs a listener that will report the supplied error message along with the reason for
|
||||
* failure to the supplied log object.
|
||||
*/
|
||||
public LoggingListener (Logger log, String errmsg)
|
||||
{
|
||||
_logger = log;
|
||||
_errmsg = errmsg;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void requestFailed (String reason)
|
||||
{
|
||||
_logger.warning(_errmsg + " [reason=" + reason + "].");
|
||||
}
|
||||
|
||||
protected Logger _logger;
|
||||
protected String _errmsg;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* A logon exception is used to indicate a failure to log on to the
|
||||
* server. The reason for failure is encoded as a string and stored in the
|
||||
* message field of the exception.
|
||||
*/
|
||||
public class LogonException extends Exception
|
||||
{
|
||||
/**
|
||||
* Constructs a logon exception with the supplied logon failure code.
|
||||
*/
|
||||
public LogonException (String code)
|
||||
{
|
||||
this(code, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a logon exception with the supplied logon failure code.
|
||||
*
|
||||
* @param stillInProgress indicates that the logon attempt has not totally
|
||||
* failed, rather we are still trying but want to report that our initial
|
||||
* attempt did not work and that we're falling back to alternative methods.
|
||||
*/
|
||||
public LogonException (String code, boolean stillInProgress)
|
||||
{
|
||||
super(code);
|
||||
_stillInProgress = stillInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this exception is reporting an intermediate status
|
||||
* rather than total logon failure. The client may be falling back to an
|
||||
* alternative port or delaying an auto-retry attempt due to server
|
||||
* overload. If this method returns true, the client <em>should not</em>
|
||||
* allow additional calls to {@link Client#logon} as the current attempt is
|
||||
* still in progress.
|
||||
*/
|
||||
public boolean isStillInProgress ()
|
||||
{
|
||||
return _stillInProgress;
|
||||
}
|
||||
|
||||
protected boolean _stillInProgress;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.threerings.presents.net.DownstreamMessage;
|
||||
import com.threerings.presents.net.UpstreamMessage;
|
||||
|
||||
/**
|
||||
* Used to listen to low-level message handling for the purpose of statistics tracking. Methods
|
||||
* must be thread-safe.
|
||||
*/
|
||||
public interface MessageTracker
|
||||
{
|
||||
/**
|
||||
* An implementation of the interface that does nothing.
|
||||
*/
|
||||
public static final MessageTracker NOOP = new MessageTracker() {
|
||||
public void messageSent (boolean datagram, int size, UpstreamMessage msg) {
|
||||
}
|
||||
public void messageReceived (
|
||||
boolean datagram, int size, DownstreamMessage msg, int missed) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Notes that a message has been sent.
|
||||
*/
|
||||
public void messageSent (boolean datagram, int size, UpstreamMessage msg);
|
||||
|
||||
/**
|
||||
* Notes that a message has been received.
|
||||
*
|
||||
* @param msg the received message, or <code>null</code> if received out of order.
|
||||
* @param missed the number of messages missed between this message and the one before it.
|
||||
*/
|
||||
public void messageReceived (boolean datagram, int size, DownstreamMessage msg, int missed);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.samskivert.util.ObserverList;
|
||||
|
||||
/**
|
||||
* Used to notify session and client observers.
|
||||
*/
|
||||
public class ObserverOps
|
||||
{
|
||||
public abstract static class Session implements ObserverList.ObserverOp<SessionObserver>
|
||||
{
|
||||
public Session (com.threerings.presents.client.Client client) {
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public boolean apply (SessionObserver obs) {
|
||||
notify(obs);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected abstract void notify (SessionObserver obs);
|
||||
|
||||
protected com.threerings.presents.client.Client _client;
|
||||
}
|
||||
|
||||
public abstract static class Client extends Session
|
||||
{
|
||||
public Client (com.threerings.presents.client.Client client) {
|
||||
super(client);
|
||||
}
|
||||
|
||||
@Override public void notify (SessionObserver obs) {
|
||||
if (obs instanceof ClientObserver) {
|
||||
notify((ClientObserver)obs);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void notify (ClientObserver obs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
import com.samskivert.util.PrefsConfig;
|
||||
|
||||
/**
|
||||
* Provides access to runtime configuration parameters for this package
|
||||
* and its subpackages.
|
||||
*/
|
||||
public class PresentsPrefs
|
||||
{
|
||||
/** Used to load our preferences from a properties file and map them
|
||||
* to the persistent Java preferences repository. */
|
||||
public static PrefsConfig config = new PrefsConfig("rsrc/config/presents");
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* A session observer is registered with the client instance to be notified when the client
|
||||
* establishes and ends their session with the server.
|
||||
*
|
||||
* @see ClientObserver
|
||||
*/
|
||||
public interface SessionObserver
|
||||
{
|
||||
/**
|
||||
* Called immediately before a logon is attempted.
|
||||
*/
|
||||
void clientWillLogon (Client client);
|
||||
|
||||
/**
|
||||
* Called after the client successfully connected to and authenticated with the server. The
|
||||
* entire object system is up and running by the time this method is called.
|
||||
*/
|
||||
void clientDidLogon (Client client);
|
||||
|
||||
/**
|
||||
* For systems that allow switching screen names after logon, this method is called whenever a
|
||||
* screen name change takes place to report that the client object has been replaced to
|
||||
* potential client-side subscribers.
|
||||
*/
|
||||
void clientObjectDidChange (Client client);
|
||||
|
||||
/**
|
||||
* Called after the client has been logged off of the server and has disconnected.
|
||||
*/
|
||||
void clientDidLogoff (Client client);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.client;
|
||||
|
||||
/**
|
||||
* Provides a means by which to obtain access to a time base object which can be used to convert
|
||||
* delta times into absolute times.
|
||||
*/
|
||||
public interface TimeBaseService extends InvocationService
|
||||
{
|
||||
/**
|
||||
* Used to communicated the result of a {@link TimeBaseService#getTimeOid} request.
|
||||
*/
|
||||
public static interface GotTimeBaseListener extends InvocationListener
|
||||
{
|
||||
/**
|
||||
* Communicates the result of a successful {@link TimeBaseService#getTimeOid} request.
|
||||
*/
|
||||
void gotTimeOid (int timeOid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests the oid of the specified time base object be fetched.
|
||||
*/
|
||||
void getTimeOid (Client client, String timeBase, GotTimeBaseListener listener);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
/**
|
||||
* Basic authentication response codes.
|
||||
*/
|
||||
public interface AuthCodes
|
||||
{
|
||||
/** A code indicating that no user exists with the specified
|
||||
* username. */
|
||||
public static final String NO_SUCH_USER = "m.no_such_user";
|
||||
|
||||
/** A code indicating that the supplied password was invalid. */
|
||||
public static final String INVALID_PASSWORD = "m.invalid_password";
|
||||
|
||||
/** A code indicating that an internal server error occurred while
|
||||
* trying to log the user on. */
|
||||
public static final String SERVER_ERROR = "m.server_error";
|
||||
|
||||
/** A code indicating that the server is not available at the moment. */
|
||||
public static final String SERVER_UNAVAILABLE = "m.server_unavailable";
|
||||
|
||||
/** A code indicating that we failed to connect to the server on a port and
|
||||
* are trying the next port in the list. */
|
||||
public static final String TRYING_NEXT_PORT = "m.trying_next_port";
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import javax.annotation.Generated;
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.client.InvocationReceiver;
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
/**
|
||||
* A distributed object to which only the client subscribes. Used to deliver messages solely to a
|
||||
* particular client as well as to publish client-specific data.
|
||||
*/
|
||||
public class ClientObject extends DObject
|
||||
{
|
||||
// AUTO-GENERATED: FIELDS START
|
||||
/** The field name of the <code>username</code> field. */
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public static final String USERNAME = "username";
|
||||
|
||||
/** The field name of the <code>receivers</code> field. */
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public static final String RECEIVERS = "receivers";
|
||||
// AUTO-GENERATED: FIELDS END
|
||||
|
||||
/** The name of a message event delivered to the client when they switch usernames (and
|
||||
* therefore user objects). */
|
||||
public static final String CLOBJ_CHANGED = "!clobj_changed!";
|
||||
|
||||
/** This client's authentication username. */
|
||||
public Name username;
|
||||
|
||||
/** Used to publish all invocation service receivers registered on this client. */
|
||||
public DSet<InvocationReceiver.Registration> receivers = DSet.newDSet();
|
||||
|
||||
/**
|
||||
* Configures this client with a permissions policy. This is done during client resolution.
|
||||
*/
|
||||
public void setPermissionPolicy (PermissionPolicy policy)
|
||||
{
|
||||
_permPolicy = policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a short string identifying this client.
|
||||
*/
|
||||
public String who ()
|
||||
{
|
||||
return "(" + username + ":" + getOid() + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not this client has the specified permission.
|
||||
*
|
||||
* @return null if the user has access, a fully-qualified translatable message string
|
||||
* indicating the reason for denial of access.
|
||||
*
|
||||
* @see PermissionPolicy
|
||||
*/
|
||||
public String checkAccess (Permission perm, Object context)
|
||||
{
|
||||
return _permPolicy.checkAccess(this, perm, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* A version of {@link #checkAccess(Permission,Object)} that provides no context.
|
||||
*/
|
||||
public String checkAccess (Permission perm)
|
||||
{
|
||||
return checkAccess(perm, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper around {@link #checkAccess(Permission,Object)} that simply returns a
|
||||
* boolean indicating whether or not this client has the permission rather than an explanation.
|
||||
*/
|
||||
public boolean hasAccess (Permission perm, Object context)
|
||||
{
|
||||
return checkAccess(perm, context) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience wrapper around {@link #checkAccess(Permission)} that simply returns a boolean
|
||||
* indicating whether or not this client has the permission rather than an explanation.
|
||||
*/
|
||||
public boolean hasAccess (Permission perm)
|
||||
{
|
||||
return checkAccess(perm) == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for reference counting client objects, adds a reference to this object.
|
||||
*/
|
||||
public synchronized void reference ()
|
||||
{
|
||||
_references++;
|
||||
// Log.info("Incremented references [who=" + who() +
|
||||
// ", refs=" + _references + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for reference counting client objects, releases a reference to
|
||||
* this object.
|
||||
*
|
||||
* @return true if the object has remaining references, false
|
||||
* otherwise.
|
||||
*/
|
||||
public synchronized boolean release ()
|
||||
{
|
||||
// Log.info("Decremented references [who=" + who() +
|
||||
// ", refs=" + (_references-1) + "].");
|
||||
return (--_references > 0);
|
||||
}
|
||||
|
||||
// AUTO-GENERATED: METHODS START
|
||||
/**
|
||||
* Requests that the <code>username</code> field be set to the
|
||||
* specified value. The local value will be updated immediately and an
|
||||
* event will be propagated through the system to notify all listeners
|
||||
* that the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void setUsername (Name value)
|
||||
{
|
||||
Name ovalue = this.username;
|
||||
requestAttributeChange(
|
||||
USERNAME, value, ovalue);
|
||||
this.username = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be added to the
|
||||
* <code>receivers</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void addToReceivers (InvocationReceiver.Registration elem)
|
||||
{
|
||||
requestEntryAdd(RECEIVERS, receivers, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the entry matching the supplied key be removed from
|
||||
* the <code>receivers</code> set. The set will not change until the
|
||||
* event is actually propagated through the system.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void removeFromReceivers (Comparable<?> key)
|
||||
{
|
||||
requestEntryRemove(RECEIVERS, receivers, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be updated in the
|
||||
* <code>receivers</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void updateReceivers (InvocationReceiver.Registration elem)
|
||||
{
|
||||
requestEntryUpdate(RECEIVERS, receivers, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>receivers</code> field be set to the
|
||||
* specified value. Generally one only adds, updates and removes
|
||||
* entries of a distributed set, but certain situations call for a
|
||||
* complete replacement of the set value. The local value will be
|
||||
* updated immediately and an event will be propagated through the
|
||||
* system to notify all listeners that the attribute did
|
||||
* change. Proxied copies of this object (on clients) will apply the
|
||||
* value change when they received the attribute changed notification.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void setReceivers (DSet<InvocationReceiver.Registration> value)
|
||||
{
|
||||
requestAttributeChange(RECEIVERS, value, this.receivers);
|
||||
DSet<InvocationReceiver.Registration> clone = (value == null) ? null : value.clone();
|
||||
this.receivers = clone;
|
||||
}
|
||||
// AUTO-GENERATED: METHODS END
|
||||
|
||||
/** Handles our fine-grained permissions. */
|
||||
protected PermissionPolicy _permPolicy;
|
||||
|
||||
/** Used to reference count resolved client objects. */
|
||||
protected transient int _references;
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
|
||||
/**
|
||||
* Used to track and report stats on the connection manager.
|
||||
*/
|
||||
public class ConMgrStats extends SimpleStreamableObject
|
||||
implements Cloneable
|
||||
{
|
||||
/** The number of mapped connections. This is a snapshot at the time the stats are requested. */
|
||||
public int connectionCount;
|
||||
|
||||
/** The number of net event handlers. This is a snapshot at the time the stats are requested. */
|
||||
public int handlerCount;
|
||||
|
||||
/** The size of the queue of waiting to auth sockets. This is a snapshot at the time the stats
|
||||
* are requested. */
|
||||
public int authQueueSize;
|
||||
|
||||
/** The size of the queue of waiting to die sockets. This is a snapshot at the time the stats
|
||||
* are requested. */
|
||||
public int deathQueueSize;
|
||||
|
||||
/** The outgoing queue size. This is a snapshot at the time the stats are requested. */
|
||||
public int outQueueSize;
|
||||
|
||||
/** The overflow queue size. This is a snapshot at the time the stats are requested. */
|
||||
public int overQueueSize;
|
||||
|
||||
/** The number of raw network events (sockets reporting ACCEPT or READY). */
|
||||
public long eventCount;
|
||||
|
||||
/** The number of connection events since the server started up. */
|
||||
public int connects;
|
||||
|
||||
/** The number of disconnection events since the server started up. */
|
||||
public int disconnects;
|
||||
|
||||
/** The number of socket closes since the server started up. */
|
||||
public int closes;
|
||||
|
||||
/** The number of bytes read since the server started up. */
|
||||
public long bytesIn;
|
||||
|
||||
/** The number of bytes written since the server started up. */
|
||||
public long bytesOut;
|
||||
|
||||
/** The number of messages read since the server started up. */
|
||||
public long msgsIn;
|
||||
|
||||
/** The number of messages written since the server started up. */
|
||||
public long msgsOut;
|
||||
|
||||
@Override // from Object
|
||||
public ConMgrStats clone ()
|
||||
{
|
||||
try {
|
||||
return (ConMgrStats) super.clone();
|
||||
} catch (CloneNotSupportedException cnse) {
|
||||
throw new AssertionError(cnse);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
/**
|
||||
* The invocation codes interface provides codes that are commonly used by invocation service
|
||||
* implementations. It is implemented as an interface so that were an invocation service to desire
|
||||
* to build on two or more other services, it can provide a codes interface that inherits from all
|
||||
* of the services that it extends.
|
||||
*/
|
||||
public interface InvocationCodes
|
||||
{
|
||||
/** Defines a global invocation services group that can be used by clients and services that do
|
||||
* not care to make a distinction between groups of invocation services. */
|
||||
public static final String GLOBAL_GROUP = "presents";
|
||||
|
||||
/** An error code returned to clients when a service cannot be performed because of some
|
||||
* internal server error that we couldn't explain in any meaningful way (things like null
|
||||
* pointer exceptions). */
|
||||
public static final String INTERNAL_ERROR = "m.internal_error";
|
||||
|
||||
/** An error code returned to clients when a service cannot be performed because the requesting
|
||||
* client does not have the proper access. */
|
||||
public static final String ACCESS_DENIED = "m.access_denied";
|
||||
|
||||
/** An error code returned to clients when a service cannot be performed because of some
|
||||
* internal server error that we couldn't explain in any meaningful way (things like null
|
||||
* pointer exceptions). */
|
||||
public static final String E_INTERNAL_ERROR = "e.internal_error";
|
||||
|
||||
/** An error code returned to clients when a service cannot be performed because the requesting
|
||||
* client does not have the proper access. */
|
||||
public static final String E_ACCESS_DENIED = "e.access_denied";
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.InvocationService;
|
||||
import com.threerings.presents.dobj.DObjectManager;
|
||||
import com.threerings.presents.dobj.InvocationResponseEvent;
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Provides a base from which all invocation service marshallers extend. Handles functionality
|
||||
* common to all marshallers.
|
||||
*/
|
||||
public class InvocationMarshaller
|
||||
implements Streamable, InvocationService
|
||||
{
|
||||
/**
|
||||
* Provides a base from which invocation listener marshallers extend.
|
||||
*/
|
||||
public static class ListenerMarshaller
|
||||
implements Streamable, InvocationListener
|
||||
{
|
||||
/** The method id used to dispatch a {@link #requestFailed} response. */
|
||||
public static final int REQUEST_FAILED_RSPID = 0;
|
||||
|
||||
/** The request id associated with this listener. */
|
||||
public short requestId;
|
||||
|
||||
/** The oid of the invocation service requester. Only used on the server. */
|
||||
public transient int callerOid;
|
||||
|
||||
/** The actual invocation listener associated with this marshalling listener. This is only
|
||||
* valid on the client. */
|
||||
public transient InvocationListener listener;
|
||||
|
||||
/** The time at which this listener marshaller was registered. This is only valid on the
|
||||
* client. */
|
||||
public transient long mapStamp;
|
||||
|
||||
/** The distributed object manager to use when dispatching proxied responses. This is only
|
||||
* valid on the server. */
|
||||
public transient DObjectManager omgr;
|
||||
|
||||
/** The transport mode through which the request was received. This is only valid on the
|
||||
* server. */
|
||||
public transient Transport transport;
|
||||
|
||||
/**
|
||||
* Set an identifier for the invocation that this listener is used for, so we can report it
|
||||
* if we are never responded-to.
|
||||
*/
|
||||
public void setInvocationId (String name)
|
||||
{
|
||||
_invId = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates that this listener will not be responded-to, and that this is normal behavior.
|
||||
*/
|
||||
public void setNoResponse ()
|
||||
{
|
||||
// we enact this by merely doing the same thing that we normally do during a response.
|
||||
_invId = null;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public void requestFailed (String cause)
|
||||
{
|
||||
_invId = null;
|
||||
omgr.postEvent(new InvocationResponseEvent(
|
||||
callerOid, requestId, REQUEST_FAILED_RSPID, new Object[] { cause }, transport));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to dispatch an invocation response to our target listener.
|
||||
*/
|
||||
public void dispatchResponse (int methodId, Object[] args)
|
||||
{
|
||||
if (methodId == REQUEST_FAILED_RSPID) {
|
||||
listener.requestFailed((String)args[0]);
|
||||
|
||||
} else {
|
||||
log.warning("Requested to dispatch unknown invocation response",
|
||||
"listener", listener, "methodId", methodId, "args", args);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[callerOid=" + callerOid + ", reqId=" + requestId +
|
||||
", type=" + getClass().getName() + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize ()
|
||||
throws Throwable
|
||||
{
|
||||
try {
|
||||
if (_invId != null && getClass() != ListenerMarshaller.class) {
|
||||
log.warning("Invocation listener never responded to: " + _invId);
|
||||
}
|
||||
} finally {
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/** On the server, the id of the invocation method. */
|
||||
protected transient String _invId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a marshaller for the standard {@link InvocationService.ConfirmListener}.
|
||||
*/
|
||||
public static class ConfirmMarshaller extends ListenerMarshaller
|
||||
implements ConfirmListener
|
||||
{
|
||||
/** The method id used to dispatch {@link #requestProcessed} responses. */
|
||||
public static final int REQUEST_PROCESSED = 1;
|
||||
|
||||
// documentation inherited from interface
|
||||
public void requestProcessed ()
|
||||
{
|
||||
_invId = null;
|
||||
omgr.postEvent(new InvocationResponseEvent(
|
||||
callerOid, requestId, REQUEST_PROCESSED, null, transport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchResponse (int methodId, Object[] args)
|
||||
{
|
||||
switch (methodId) {
|
||||
case REQUEST_PROCESSED:
|
||||
((ConfirmListener)listener).requestProcessed();
|
||||
return;
|
||||
|
||||
default:
|
||||
super.dispatchResponse(methodId, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines a marshaller for the standard {@link InvocationService.ResultListener}.
|
||||
*/
|
||||
public static class ResultMarshaller extends ListenerMarshaller
|
||||
implements ResultListener
|
||||
{
|
||||
/** The method id used to dispatch {@link #requestProcessed} responses. */
|
||||
public static final int REQUEST_PROCESSED = 1;
|
||||
|
||||
// documentation inherited from interface
|
||||
public void requestProcessed (Object result)
|
||||
{
|
||||
_invId = null;
|
||||
omgr.postEvent(new InvocationResponseEvent(
|
||||
callerOid, requestId, REQUEST_PROCESSED, new Object[] { result }, transport));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchResponse (int methodId, Object[] args)
|
||||
{
|
||||
switch (methodId) {
|
||||
case REQUEST_PROCESSED:
|
||||
((ResultListener)listener).requestProcessed(args[0]);
|
||||
return;
|
||||
|
||||
default:
|
||||
super.dispatchResponse(methodId, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this invocation marshaller instance with the requisite information to allow it
|
||||
* to operate in the wide world. This is called by the invocation manager when an invocation
|
||||
* provider is registered and should not be called otherwise.
|
||||
*/
|
||||
public void init (int invOid, int invCode)
|
||||
{
|
||||
_invOid = invOid;
|
||||
_invCode = invCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the invocation oid to which this marshaller should send its invocation service
|
||||
* requests. This is called by the invocation manager in certain initialization circumstances.
|
||||
*/
|
||||
public void setInvocationOid (int invOid)
|
||||
{
|
||||
_invOid = invOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the code assigned to this marshaller.
|
||||
*/
|
||||
public int getInvocationCode ()
|
||||
{
|
||||
return _invCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method to indicate that the listener is not going to be responded-to, and that
|
||||
* this is ok.
|
||||
*/
|
||||
public static void setNoResponse (InvocationListener listener)
|
||||
{
|
||||
if (listener instanceof ListenerMarshaller) {
|
||||
((ListenerMarshaller) listener).setNoResponse();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[invOid=" + _invOid + ", code=" + _invCode + ", type=" + getClass().getName() + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by generated invocation marshaller code; packages up and sends the specified
|
||||
* invocation service request.
|
||||
*/
|
||||
protected void sendRequest (Client client, int methodId, Object[] args)
|
||||
{
|
||||
sendRequest(client, methodId, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by generated invocation marshaller code; packages up and sends the specified
|
||||
* invocation service request.
|
||||
*/
|
||||
protected void sendRequest (Client client, int methodId, Object[] args, Transport transport)
|
||||
{
|
||||
client.getInvocationDirector().sendRequest(_invOid, _invCode, methodId, args, transport);
|
||||
}
|
||||
|
||||
/** The oid of the invocation object, where invocation service requests are sent. */
|
||||
protected int _invOid;
|
||||
|
||||
/** The invocation service code assigned to this service when it was registered on the
|
||||
* server. */
|
||||
protected int _invCode;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
|
||||
/**
|
||||
* A single invocation object is created by the server invocation manager
|
||||
* and is used to receive invocation request messages from the client. The
|
||||
* server presently delivers invocation messages to the client via the
|
||||
* client object.
|
||||
*/
|
||||
public class InvocationObject extends DObject
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
/**
|
||||
* A value class used by {@link ClientObject#checkAccess(Permission)} to do fine-grained access
|
||||
* control.
|
||||
*/
|
||||
public class Permission
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
/**
|
||||
* Encapsulates a fine-grained permissions policy. The default policy is to deny access to
|
||||
* everything, systems using fine-grained permissions should create a custom policy and provide it
|
||||
* at client resolution time via the ClientResolver.
|
||||
*/
|
||||
public class PermissionPolicy
|
||||
implements Streamable, InvocationCodes
|
||||
{
|
||||
/**
|
||||
* Returns null if the specified client has the specified permission, an error code explaining
|
||||
* the lack of access if they do not. {@link InvocationCodes#ACCESS_DENIED} should be returned
|
||||
* if no more specific explanation is available.
|
||||
*
|
||||
* @param clobj the client
|
||||
* @param perm what permission they'd like to know if they have
|
||||
* @param context potential context for the request, if that matters
|
||||
*/
|
||||
public String checkAccess (ClientObject clobj, Permission perm, Object context)
|
||||
{
|
||||
// by default, you can't do it!
|
||||
return ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
/**
|
||||
* Codes and constants relating to the Presents time base services.
|
||||
*/
|
||||
public interface TimeBaseCodes extends InvocationCodes
|
||||
{
|
||||
/** An error response generated for GetTimeOid requests. */
|
||||
public static final String NO_SUCH_TIME_BASE = "m.no_such_time_base";
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import javax.annotation.Generated;
|
||||
|
||||
import com.threerings.presents.client.Client;
|
||||
import com.threerings.presents.client.TimeBaseService;
|
||||
import com.threerings.presents.dobj.InvocationResponseEvent;
|
||||
|
||||
/**
|
||||
* Provides the implementation of the {@link TimeBaseService} interface
|
||||
* that marshalls the arguments and delivers the request to the provider
|
||||
* on the server. Also provides an implementation of the response listener
|
||||
* interfaces that marshall the response arguments and deliver them back
|
||||
* to the requesting client.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenServiceTask"},
|
||||
comments="Derived from TimeBaseService.java.")
|
||||
public class TimeBaseMarshaller extends InvocationMarshaller
|
||||
implements TimeBaseService
|
||||
{
|
||||
/**
|
||||
* Marshalls results to implementations of {@link TimeBaseService.GotTimeBaseListener}.
|
||||
*/
|
||||
public static class GotTimeBaseMarshaller extends ListenerMarshaller
|
||||
implements GotTimeBaseListener
|
||||
{
|
||||
/** The method id used to dispatch {@link #gotTimeOid}
|
||||
* responses. */
|
||||
public static final int GOT_TIME_OID = 1;
|
||||
|
||||
// from interface GotTimeBaseMarshaller
|
||||
public void gotTimeOid (int arg1)
|
||||
{
|
||||
_invId = null;
|
||||
omgr.postEvent(new InvocationResponseEvent(
|
||||
callerOid, requestId, GOT_TIME_OID,
|
||||
new Object[] { Integer.valueOf(arg1) }, transport));
|
||||
}
|
||||
|
||||
@Override // from InvocationMarshaller
|
||||
public void dispatchResponse (int methodId, Object[] args)
|
||||
{
|
||||
switch (methodId) {
|
||||
case GOT_TIME_OID:
|
||||
((GotTimeBaseListener)listener).gotTimeOid(
|
||||
((Integer)args[0]).intValue());
|
||||
return;
|
||||
|
||||
default:
|
||||
super.dispatchResponse(methodId, args);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The method id used to dispatch {@link #getTimeOid} requests. */
|
||||
public static final int GET_TIME_OID = 1;
|
||||
|
||||
// from interface TimeBaseService
|
||||
public void getTimeOid (Client arg1, String arg2, TimeBaseService.GotTimeBaseListener arg3)
|
||||
{
|
||||
TimeBaseMarshaller.GotTimeBaseMarshaller listener3 = new TimeBaseMarshaller.GotTimeBaseMarshaller();
|
||||
listener3.listener = arg3;
|
||||
sendRequest(arg1, GET_TIME_OID, new Object[] {
|
||||
arg2, listener3
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.data;
|
||||
|
||||
import javax.annotation.Generated;
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
|
||||
/**
|
||||
* Used to communicate time bases to clients so that more efficient delta
|
||||
* times can be transmitted over the network. Two time stamps are
|
||||
* maintained: even and odd. When the even time base is sufficiently old
|
||||
* that our delta time container (usually a short or an int) will exceed
|
||||
* its maximum value, we switch to the odd time base. The bouncing between
|
||||
* two separate values prevents problems from arising when the base time
|
||||
* is changed, yet values using the old base time might still be
|
||||
* propagating through the system.
|
||||
*
|
||||
* <p> Note that for sufficiently small delta time containers, stale
|
||||
* values could still linger longer than the time required for two swaps
|
||||
* (two byte delta stamps for example, must swap every 30 seconds).
|
||||
*/
|
||||
public class TimeBaseObject extends DObject
|
||||
{
|
||||
// AUTO-GENERATED: FIELDS START
|
||||
/** The field name of the <code>evenBase</code> field. */
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public static final String EVEN_BASE = "evenBase";
|
||||
|
||||
/** The field name of the <code>oddBase</code> field. */
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public static final String ODD_BASE = "oddBase";
|
||||
// AUTO-GENERATED: FIELDS END
|
||||
|
||||
/** The even time base, used to decode even delta times. */
|
||||
public long evenBase;
|
||||
|
||||
/** The odd time base, used to decode odd delta times. */
|
||||
public long oddBase;
|
||||
|
||||
/**
|
||||
* Converts the supplied time stamp into a time delta (measured
|
||||
* relative to the appropriate time base, even or odd) with maximum
|
||||
* value of 2^15. (One bit must be used to indicate that it is an even
|
||||
* or odd time stamp).
|
||||
*/
|
||||
public short toShortDelta (long timeStamp)
|
||||
{
|
||||
return (short)getDelta(timeStamp, Short.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the supplied time stamp into a time delta (measured
|
||||
* relative to the appropriate time base, even or odd) with maximum
|
||||
* value of 2^31. (One bit must be used to indicate that it is an even
|
||||
* or odd time stamp).
|
||||
*/
|
||||
public int toIntDelta (long timeStamp)
|
||||
{
|
||||
return (int)getDelta(timeStamp, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the supplied delta time back to a wall time based on the
|
||||
* base time in this time base object. Either an int or short delta
|
||||
* can be passed to this method (the short will have been promoted to
|
||||
* an int in the process but that will not mess up its encoded value).
|
||||
*/
|
||||
public long fromDelta (int delta)
|
||||
{
|
||||
boolean even = (delta > 0);
|
||||
long time = even ? evenBase : oddBase;
|
||||
if (even) {
|
||||
time += delta;
|
||||
} else {
|
||||
time += (-1 - delta);
|
||||
}
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtains a delta with the specified maximum value, swapping from
|
||||
* even to odd, if necessary.
|
||||
*/
|
||||
protected long getDelta (long timeStamp, long maxValue)
|
||||
{
|
||||
boolean even = (evenBase > oddBase);
|
||||
long base = even ? evenBase : oddBase;
|
||||
long delta = timeStamp - base;
|
||||
|
||||
// make sure this timestamp is not sufficiently old that we can't
|
||||
// generate a delta time with it
|
||||
if (delta < 0) {
|
||||
String errmsg = "Time stamp too old for conversion to delta time";
|
||||
throw new IllegalArgumentException(errmsg);
|
||||
}
|
||||
|
||||
// see if it's time to swap
|
||||
if (delta > maxValue) {
|
||||
if (even) {
|
||||
setOddBase(timeStamp);
|
||||
} else {
|
||||
setEvenBase(timeStamp);
|
||||
}
|
||||
delta = 0;
|
||||
}
|
||||
|
||||
// if we're odd, we need to mark the value as such
|
||||
if (!even) {
|
||||
delta = (-1 - delta);
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
|
||||
// AUTO-GENERATED: METHODS START
|
||||
/**
|
||||
* Requests that the <code>evenBase</code> field be set to the
|
||||
* specified value. The local value will be updated immediately and an
|
||||
* event will be propagated through the system to notify all listeners
|
||||
* that the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void setEvenBase (long value)
|
||||
{
|
||||
long ovalue = this.evenBase;
|
||||
requestAttributeChange(
|
||||
EVEN_BASE, Long.valueOf(value), Long.valueOf(ovalue));
|
||||
this.evenBase = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>oddBase</code> field be set to the
|
||||
* specified value. The local value will be updated immediately and an
|
||||
* event will be propagated through the system to notify all listeners
|
||||
* that the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
@Generated(value={"com.threerings.presents.tools.GenDObjectTask"})
|
||||
public void setOddBase (long value)
|
||||
{
|
||||
long ovalue = this.oddBase;
|
||||
requestAttributeChange(
|
||||
ODD_BASE, Long.valueOf(value), Long.valueOf(ovalue));
|
||||
this.oddBase = value;
|
||||
}
|
||||
// AUTO-GENERATED: METHODS END
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Used to validate distributed object subscription requests and event
|
||||
* dispatches.
|
||||
*
|
||||
* @see DObject#setAccessController
|
||||
*/
|
||||
public interface AccessController
|
||||
{
|
||||
/**
|
||||
* Should return true if the supplied subscriber is allowed to
|
||||
* subscribe to the specified object.
|
||||
*/
|
||||
boolean allowSubscribe (DObject object, Subscriber<?> subscriber);
|
||||
|
||||
/**
|
||||
* Should return true if the supplied event is legal for dispatch on
|
||||
* the specified distributed object.
|
||||
*/
|
||||
boolean allowDispatch (DObject object, DEvent event);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about attribute changes that take place for a
|
||||
* particular distributed object.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface AttributeChangeListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when an attribute changed event has been dispatched on an object. This will be
|
||||
* called <em>after</em> the event has been applied to the object. So fetching the attribute
|
||||
* during this call will provide the new value for the attribute.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void attributeChanged (AttributeChangedEvent event);
|
||||
}
|
||||
@@ -0,0 +1,206 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* An attribute changed event is dispatched when a single attribute of a distributed object has
|
||||
* changed. It can also be constructed to request an attribute change on an object and posted to
|
||||
* the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class AttributeChangedEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for unserialization from the
|
||||
* network.
|
||||
*/
|
||||
public AttributeChangedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute.
|
||||
*/
|
||||
public Object getValue ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the attribute prior to the application of this event.
|
||||
*/
|
||||
public Object getOldValue ()
|
||||
{
|
||||
return _oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as a byte. This will fail if the attribute in
|
||||
* question is not a byte.
|
||||
*/
|
||||
public byte getByteValue ()
|
||||
{
|
||||
return ((Byte)_value).byteValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as a short. This will fail if the attribute in
|
||||
* question is not a short.
|
||||
*/
|
||||
public short getShortValue ()
|
||||
{
|
||||
return ((Short)_value).shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as an int. This will fail if the attribute in
|
||||
* question is not an int.
|
||||
*/
|
||||
public int getIntValue ()
|
||||
{
|
||||
return ((Integer)_value).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as a long. This will fail if the attribute in
|
||||
* question is not a long.
|
||||
*/
|
||||
public long getLongValue ()
|
||||
{
|
||||
return ((Long)_value).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as a float. This will fail if the attribute in
|
||||
* question is not a float.
|
||||
*/
|
||||
public float getFloatValue ()
|
||||
{
|
||||
return ((Float)_value).floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the attribute as a double. This will fail if the attribute in
|
||||
* question is not a double.
|
||||
*/
|
||||
public double getDoubleValue ()
|
||||
{
|
||||
return ((Double)_value).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
// if we have an old value, that means we're running on the master server and we have
|
||||
// already applied this attribute change to the object
|
||||
return (_oldValue != UNSET_OLD_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// if we're not already applied, grab the previous value and apply the attribute change
|
||||
if (!alreadyApplied()) {
|
||||
_oldValue = target.getAttribute(_name);
|
||||
Object value = _value;
|
||||
if (value != null) {
|
||||
Class<?> vclass = value.getClass();
|
||||
if (vclass.isPrimitive()) {
|
||||
// do nothing; we check this to avoid the more expensive isAssignableFrom check
|
||||
// on primitives which are far and away the most common case
|
||||
} else if (vclass.isArray()) {
|
||||
int length = Array.getLength(value);
|
||||
Object clone = Array.newInstance(vclass.getComponentType(), length);
|
||||
System.arraycopy(value, 0, clone, 0, length);
|
||||
value = clone;
|
||||
} else if (DSet.class.isAssignableFrom(vclass)) {
|
||||
value = ((DSet<?>)value).clone();
|
||||
}
|
||||
}
|
||||
// pass the new value on to the object
|
||||
target.setAttribute(_name, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new attribute changed event on the specified target object with the supplied
|
||||
* attribute name and value. <em>Do not construct these objects by hand.</em> Use {@link
|
||||
* DObject#changeAttribute} instead.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has changed.
|
||||
* @param name the name of the attribute (data member) that has changed.
|
||||
* @param value the new value of the attribute (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
*/
|
||||
protected AttributeChangedEvent (int targetOid, String name, Object value, Object oldValue)
|
||||
{
|
||||
this(targetOid, name, value, oldValue, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new attribute changed event on the specified target object with the supplied
|
||||
* attribute name and value. <em>Do not construct these objects by hand.</em> Use {@link
|
||||
* DObject#changeAttribute} instead.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has changed.
|
||||
* @param name the name of the attribute (data member) that has changed.
|
||||
* @param value the new value of the attribute (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
protected AttributeChangedEvent (
|
||||
int targetOid, String name, Object value, Object oldValue, Transport transport)
|
||||
{
|
||||
super(targetOid, name, transport);
|
||||
_value = value;
|
||||
_oldValue = oldValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof AttributeChangeListener) {
|
||||
((AttributeChangeListener)listener).attributeChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("CHANGE:");
|
||||
super.toString(buf);
|
||||
buf.append(", value=");
|
||||
StringUtil.toString(buf, _value);
|
||||
}
|
||||
|
||||
protected Object _value;
|
||||
protected transient Object _oldValue = UNSET_OLD_VALUE;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* The various listener interfaces (e.g. {@link EventListener}, {@link AttributeChangeListener},
|
||||
* etc.) all extend this base interface so that the distributed object can check to make sure when
|
||||
* an object is adding itself as a listener of some sort that it actually implements at least one
|
||||
* of the listener interfaces. Thus, all listener interfaces must extend this one.
|
||||
*/
|
||||
public interface ChangeListener
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.threerings.util.StreamableArrayList;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* Used to manage and submit groups of events on a collection of distributed objects in a single
|
||||
* transaction.
|
||||
*
|
||||
* @see DObject#startTransaction
|
||||
*/
|
||||
public class CompoundEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a blank compound event in preparation for unserialization.
|
||||
*/
|
||||
public CompoundEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a compound event and prepares it for operation.
|
||||
*/
|
||||
public CompoundEvent (DObject target, DObjectManager omgr)
|
||||
{
|
||||
super(target.getOid());
|
||||
|
||||
// sanity check
|
||||
if (omgr == null) {
|
||||
String errmsg = "Must receive non-null object manager reference";
|
||||
throw new IllegalArgumentException(errmsg);
|
||||
}
|
||||
|
||||
_omgr = omgr;
|
||||
_target = target;
|
||||
_events = StreamableArrayList.newList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Posts an event to this transaction. The event will be delivered as part of the entire
|
||||
* transaction if it is committed or discarded if the transaction is cancelled.
|
||||
*/
|
||||
public void postEvent (DEvent event)
|
||||
{
|
||||
_events.add(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of events contained within this compound event.
|
||||
*
|
||||
* Don't mess with it.
|
||||
*/
|
||||
public List<DEvent> getEvents ()
|
||||
{
|
||||
return _events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Commits this transaction by posting this event to the distributed object event queue. All
|
||||
* participating dobjects will have their transaction references cleared and will go back to
|
||||
* normal operation.
|
||||
*/
|
||||
public void commit ()
|
||||
{
|
||||
// first clear our target
|
||||
clearTarget();
|
||||
|
||||
// then post this event onto the queue (but only if we actually
|
||||
// accumulated some events)
|
||||
int size = _events.size();
|
||||
switch (size) {
|
||||
case 0: // nothing doing
|
||||
break;
|
||||
case 1: // no point in being compound
|
||||
_omgr.postEvent(_events.get(0));
|
||||
break;
|
||||
default: // now we're talking
|
||||
_transport = _events.get(0).getTransport();
|
||||
for (int ii = 1; ii < size; ii++) {
|
||||
_transport = _events.get(ii).getTransport().combine(_transport);
|
||||
}
|
||||
_omgr.postEvent(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels this transaction. All events posted to this transaction will be discarded.
|
||||
*/
|
||||
public void cancel ()
|
||||
{
|
||||
// clear our target
|
||||
clearTarget();
|
||||
// clear our event queue in case someone holds onto us
|
||||
_events.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSourceOid (int sourceOid)
|
||||
{
|
||||
super.setSourceOid(sourceOid);
|
||||
|
||||
// we need to propagate our source oid to our constituent events
|
||||
int ecount = _events.size();
|
||||
for (int ii = 0; ii < ecount; ii++) {
|
||||
_events.get(ii).setSourceOid(sourceOid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTargetOid (int targetOid)
|
||||
{
|
||||
super.setTargetOid(targetOid);
|
||||
|
||||
// we need to propagate our target oid to our constituent events
|
||||
int ecount = _events.size();
|
||||
for (int ii = 0; ii < ecount; ii++) {
|
||||
_events.get(ii).setTargetOid(targetOid);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
super.setTransport(transport);
|
||||
for (int ii = 0, nn = _events.size(); ii < nn; ii++) {
|
||||
_events.get(ii).setTransport(transport);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to apply here
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls out to our target object, clearing its transaction reference.
|
||||
*/
|
||||
protected void clearTarget ()
|
||||
{
|
||||
if (_target != null) {
|
||||
_target.clearTransaction();
|
||||
_target = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("COMPOUND:");
|
||||
super.toString(buf);
|
||||
for (int ii = 0; ii < _events.size(); ii++) {
|
||||
buf.append(", ").append(_events.get(ii));
|
||||
}
|
||||
}
|
||||
|
||||
/** The object manager that we'll post ourselves to when we're committed. */
|
||||
protected transient DObjectManager _omgr;
|
||||
|
||||
/** The object for which we're managing a transaction. */
|
||||
protected transient DObject _target;
|
||||
|
||||
/** A list of the events associated with this compound event. */
|
||||
protected StreamableArrayList<DEvent> _events;
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* A distributed object event is dispatched whenever any modification is made to a distributed
|
||||
* object. It can also be dispatched purely for notification purposes, without making any
|
||||
* modifications to the object that defines the delivery group (the object's subscribers).
|
||||
*/
|
||||
public abstract class DEvent implements Streamable
|
||||
{
|
||||
/** This event's "number". Every event dispatched by the server is numbered in monotonically
|
||||
* increasing fashion when the event is posted to the event dispatch queue. */
|
||||
public transient long eventId;
|
||||
|
||||
/**
|
||||
* A zero argument constructor for unserialization from yon network.
|
||||
*/
|
||||
public DEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new distributed object event that pertains to the specified distributed object.
|
||||
*/
|
||||
public DEvent (int targetOid)
|
||||
{
|
||||
this(targetOid, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new distributed object event that pertains to the specified distributed object.
|
||||
*
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public DEvent (int targetOid, Transport transport)
|
||||
{
|
||||
_toid = targetOid;
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid of the object that is the target of this event.
|
||||
*/
|
||||
public int getTargetOid ()
|
||||
{
|
||||
return _toid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some events are used only internally on the server and need not be broadcast to subscribers,
|
||||
* proxy or otherwise. Such events can return true here and short-circuit the normal proxy
|
||||
* event dispatch mechanism.
|
||||
*/
|
||||
public boolean isPrivate ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this event applies itself immediately to the distributed object on the server and then
|
||||
* NOOPs later when {@link #applyToObject} is called, it should return true from this method.
|
||||
* If it will modify the object during its {@link #applyToObject} call, it should return false.
|
||||
*/
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the attribute modifications represented by this event to the specified target
|
||||
* object. This is called by the distributed object manager in the course of dispatching events
|
||||
* and should not be called directly.
|
||||
*
|
||||
* @exception ObjectAccessException thrown if there is any problem applying the event to the
|
||||
* object (invalid attribute, etc.).
|
||||
*
|
||||
* @return true if the object manager should go on to notify the object's listeners of this
|
||||
* event, false if the event should be treated silently and the listeners should not be
|
||||
* notified.
|
||||
*/
|
||||
public abstract boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException;
|
||||
|
||||
/**
|
||||
* Returns the object id of the client that generated this event. If the event was generated by
|
||||
* the server, the value returned will be -1. This is not valid on the client, it will return
|
||||
* -1 for all events there (it is primarily provided to allow for event-level access control).
|
||||
*/
|
||||
public int getSourceOid ()
|
||||
{
|
||||
return _soid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not call this method. Sets the oid of the object on which this event operates. It is only
|
||||
* used when rewriting events during object proxying.
|
||||
*/
|
||||
public void setTargetOid (int targetOid)
|
||||
{
|
||||
_toid = targetOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not call this method. Sets the source oid of the client that generated this event. It is
|
||||
* automatically called by the client management code when a client forwards an event to the
|
||||
* server.
|
||||
*/
|
||||
public void setSourceOid (int sourceOid)
|
||||
{
|
||||
_soid = sourceOid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the transport parameters. For events received over the network, these indicate the
|
||||
* mode of transport over which the event was received. When an event is sent over the
|
||||
* network, these act as a hint as to the type of transport desired.
|
||||
*/
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport parameters.
|
||||
*/
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return _transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notes the actual transport with which the event was transmitted.
|
||||
*/
|
||||
public void noteActualTransport (Transport transport)
|
||||
{
|
||||
_actualTransport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the actual transport with which the event was transmitted, or <code>null</code> if
|
||||
* not yet known.
|
||||
*/
|
||||
public Transport getActualTransport ()
|
||||
{
|
||||
return _actualTransport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Events with associated listener interfaces should implement this function and notify the
|
||||
* supplied listener if it implements their event listening interface. For example, the {@link
|
||||
* AttributeChangedEvent} will notify listeners that implement {@link AttributeChangeListener}.
|
||||
*/
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
// the default is to do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("[");
|
||||
toString(buf);
|
||||
buf.append("]");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This should be overridden by derived classes (which should be sure to call
|
||||
* <code>super.toString()</code>) to append the derived class specific event information to the
|
||||
* string buffer.
|
||||
*/
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("targetOid=").append(_toid);
|
||||
buf.append(", sourceOid=").append(_soid);
|
||||
if (_transport != Transport.DEFAULT) {
|
||||
buf.append(", transport=").append(_transport);
|
||||
}
|
||||
}
|
||||
|
||||
/** The oid of the object that is the target of this event. */
|
||||
protected int _toid;
|
||||
|
||||
/** The oid of the client that generated this event. */
|
||||
protected transient int _soid = -1;
|
||||
|
||||
/** The transport parameters. */
|
||||
protected transient Transport _transport = Transport.DEFAULT;
|
||||
|
||||
/** The actual transport with which the event was transmitted (null if as yet unknown). */
|
||||
protected transient Transport _actualTransport;
|
||||
|
||||
/** Used to differentiate between null meaning we haven't initialized our old value and null
|
||||
* being the actual old value. */
|
||||
protected static final Object UNSET_OLD_VALUE = new Object();
|
||||
|
||||
/** Used to differentiate between null meaning we haven't initialized our old entry and null
|
||||
* being the actual old entry. */
|
||||
protected static final DSet.Entry UNSET_OLD_ENTRY = new DSet.Entry() {
|
||||
public Comparable<?> getKey () {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* The distributed object manager is responsible for managing the creation and destruction of
|
||||
* distributed objects and propagating dobj events to the appropriate subscribers. On the client,
|
||||
* objects are managed as proxies to the real objects managed by the server, so attribute change
|
||||
* requests are forwarded to the server and events coming down from the server are delivered to the
|
||||
* local subscribers. On the server, the objects are managed directly.
|
||||
*/
|
||||
public interface DObjectManager
|
||||
{
|
||||
/**
|
||||
* Returns true if this distributed object manager is the authoritative manager for the
|
||||
* specified distributed object, or fals if we are only providing a proxy to the object.
|
||||
*/
|
||||
boolean isManager (DObject object);
|
||||
|
||||
/**
|
||||
* Requests that the specified subscriber be subscribed to the object identified by the
|
||||
* supplied object id. That subscriber will be notified when the object is available or if the
|
||||
* subscription request failed.
|
||||
*
|
||||
* @param oid The object id of the distributed object to which subscription is desired.
|
||||
* @param target The subscriber to be subscribed.
|
||||
*
|
||||
* @see Subscriber#objectAvailable
|
||||
* @see Subscriber#requestFailed
|
||||
*/
|
||||
<T extends DObject> void subscribeToObject (int oid, Subscriber<T> target);
|
||||
|
||||
/**
|
||||
* Requests that the specified subscriber be unsubscribed from the object identified by the
|
||||
* supplied object id.
|
||||
*
|
||||
* @param oid The object id of the distributed object from which unsubscription is desired.
|
||||
* @param target The subscriber to be unsubscribed.
|
||||
*/
|
||||
<T extends DObject> void unsubscribeFromObject (int oid, Subscriber<T> target);
|
||||
|
||||
/**
|
||||
* Posts a distributed object event into the system. Instead of requesting the modification of
|
||||
* a distributed object attribute by calling the setter for that attribute on the object
|
||||
* itself, an <code>AttributeChangedEvent</code> can be constructed and posted directly. This
|
||||
* is true for all event types and is useful for situations where one doesn't have access to
|
||||
* the object in question, but needs to affect some event.
|
||||
*
|
||||
* <p> This event will be forwarded to the ultimate manager of the object (on the client, this
|
||||
* means it will be forwarded to the server) where it will be checked for validity and then
|
||||
* applied to the object and dispatched to all its subscribers.
|
||||
*
|
||||
* @param event The event to be dispatched.
|
||||
*/
|
||||
void postEvent (DEvent event);
|
||||
|
||||
/**
|
||||
* When a distributed object removes its last subscriber, it will call this function to let the
|
||||
* object manager know. The manager might then choose to flush this object from the system or
|
||||
* unregister from some upstream manager whose object it was proxying, for example.
|
||||
*/
|
||||
void removedLastSubscriber (DObject obj, boolean deathWish);
|
||||
}
|
||||
@@ -0,0 +1,530 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.util.AbstractSet;
|
||||
import java.util.Comparator;
|
||||
import java.util.ConcurrentModificationException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.samskivert.util.ArrayUtil;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
import com.threerings.io.ObjectOutputStream;
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* The distributed set class provides a means by which an unordered set of objects can be
|
||||
* maintained as a distributed object field. Entries can be added to and removed from the set,
|
||||
* requests for which will generate events much like other distributed object fields.
|
||||
*
|
||||
* <p> Classes that wish to act as set entries must implement the {@link Entry} interface which
|
||||
* extends {@link Streamable} and adds the requirement that the object provide a key which will be
|
||||
* used to identify entry equality. Thus an entry is declared to be in a set of the object returned
|
||||
* by that entry's {@link Entry#getKey} method is equal (using {@link Object#equals}) to the entry
|
||||
* returned by the {@link Entry#getKey} method of some other entry in the set. Additionally, in the
|
||||
* case of entry removal, only the key for the entry to be removed will be transmitted with the
|
||||
* removal event to save network bandwidth. Lastly, the object returned by {@link Entry#getKey}
|
||||
* must be a {@link Streamable} type.
|
||||
*
|
||||
* @param <E> the type of entry stored in this set.
|
||||
*/
|
||||
public class DSet<E extends DSet.Entry>
|
||||
implements Iterable<E>, Streamable, Cloneable
|
||||
{
|
||||
/**
|
||||
* Entries of the set must implement this interface.
|
||||
*/
|
||||
public static interface Entry extends Streamable
|
||||
{
|
||||
/**
|
||||
* Each entry provide an associated key which is used to determine its uniqueness in the
|
||||
* set. See the {@link DSet} class documentation for further information.
|
||||
*/
|
||||
Comparable<?> getKey ();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DSet of the appropriate generic type.
|
||||
*/
|
||||
public static <E extends DSet.Entry> DSet<E> newDSet ()
|
||||
{
|
||||
return new DSet<E>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DSet of the appropriate generic type.
|
||||
*/
|
||||
public static <E extends DSet.Entry> DSet<E> newDSet (Iterable<E> source)
|
||||
{
|
||||
return new DSet<E>(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the first comparable to the second. This is useful to avoid type safety warnings
|
||||
* when dealing with the keys of {@link DSet.Entry} values.
|
||||
*/
|
||||
public static int compare (Comparable<?> c1, Comparable<?> c2)
|
||||
{
|
||||
@SuppressWarnings("unchecked") Comparable<Object> cc1 = (Comparable<Object>)c1;
|
||||
@SuppressWarnings("unchecked") Comparable<Object> cc2 = (Comparable<Object>)c2;
|
||||
return cc1.compareTo(cc2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a distributed set and populates it with values from the supplied iterator. This
|
||||
* should be done before the set is unleashed into the wild distributed object world because no
|
||||
* associated entry added events will be generated. Additionally, this operation does not check
|
||||
* for duplicates when adding entries, so one should be sure that the iterator contains only
|
||||
* unique entries.
|
||||
*
|
||||
* @param source an iterator from which we will initially populate the set.
|
||||
*/
|
||||
public DSet (Iterable<E> source)
|
||||
{
|
||||
for (E e : source) {
|
||||
add(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a distributed set and populates it with values from the supplied iterator. This
|
||||
* should be done before the set is unleashed into the wild distributed object world because no
|
||||
* associated entry added events will be generated. Additionally, this operation does not check
|
||||
* for duplicates when adding entries, so one should be sure that the iterator contains only
|
||||
* unique entries.
|
||||
*
|
||||
* @param source an iterator from which we will initially populate the set.
|
||||
*/
|
||||
public DSet (Iterator<E> source)
|
||||
{
|
||||
while (source.hasNext()) {
|
||||
add(source.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a distributed set and populates it with values from the supplied array. This should
|
||||
* be done before the set is unleashed into the wild distributed object world because no
|
||||
* associated entry added events will be generated. Additionally, this operation does not check
|
||||
* for duplicates when adding entries, so one should be sure that the iterator contains only
|
||||
* unique entries.
|
||||
*
|
||||
* @param source an array from which we will initially populate the set.
|
||||
*/
|
||||
public DSet (E[] source)
|
||||
{
|
||||
for (E element : source) {
|
||||
if (element != null) {
|
||||
add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an empty distributed set.
|
||||
*/
|
||||
public DSet ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of entries in this set.
|
||||
*/
|
||||
public int size ()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the set contains an entry whose <code>getKey()</code> method returns a key
|
||||
* that <code>equals()</code> the key returned by <code>getKey()</code> of the supplied
|
||||
* entry. Returns false otherwise.
|
||||
*/
|
||||
public boolean contains (E elem)
|
||||
{
|
||||
return containsKey(elem.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an entry in the set has a key that <code>equals()</code> the supplied
|
||||
* key. Returns false otherwise.
|
||||
*/
|
||||
public boolean containsKey (Comparable<?> key)
|
||||
{
|
||||
return get(key) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry that matches (<code>getKey().equals(key)</code>) the specified key or null
|
||||
* if no entry could be found that matches the key.
|
||||
*/
|
||||
public E get (Comparable<?> key)
|
||||
{
|
||||
// determine where we'll be adding the new element
|
||||
int eidx = ArrayUtil.binarySearch(
|
||||
_entries, 0, _size, new SimpleEntry<Comparable<?>>(key), ENTRY_COMP);
|
||||
return (eidx < 0) ? null : _entries[eidx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the entries of this set. It does not support modification (nor
|
||||
* iteration while modifications are being made to the set). It should not be kept around as it
|
||||
* can quickly become out of date.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public Iterator<E> entries ()
|
||||
{
|
||||
return iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator over the entries of this set. It does not support modification (nor
|
||||
* iteration while modifications are being made to the set). It should not be kept around as it
|
||||
* can quickly become out of date.
|
||||
*/
|
||||
public Iterator<E> iterator ()
|
||||
{
|
||||
// the crazy sanity checks
|
||||
if (_size < 0 || _size > _entries.length || (_size > 0 && _entries[_size-1] == null)) {
|
||||
log.warning("DSet in a bad way", "size", _size, "entries", _entries, new Exception());
|
||||
}
|
||||
|
||||
return new Iterator<E>() {
|
||||
public boolean hasNext () {
|
||||
checkComodification();
|
||||
return (_index < _size);
|
||||
}
|
||||
public E next () {
|
||||
checkComodification();
|
||||
return _entries[_index++];
|
||||
}
|
||||
public void remove () {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
protected void checkComodification () {
|
||||
if (_modCount != _expectedModCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
if (_ssize != _size) {
|
||||
log.warning("Size changed during iteration", "ssize", _ssize, "nsize", _size,
|
||||
"entries", _entries, new Exception());
|
||||
}
|
||||
}
|
||||
protected int _index = 0;
|
||||
protected int _ssize = _size;
|
||||
protected int _expectedModCount = _modCount;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies the elements of this distributed set into the supplied array. If the array is not
|
||||
* large enough to hold all of the elements, as many as fit into the array will be copied. If
|
||||
* the <code>array</code> argument is null, an object array of sufficient size to contain all
|
||||
* of the elements of this set will be created and returned.
|
||||
*/
|
||||
public E[] toArray (E[] array)
|
||||
{
|
||||
if (array == null) {
|
||||
@SuppressWarnings("unchecked") E[] copy = (E[])new Entry[size()];
|
||||
array = copy;
|
||||
}
|
||||
System.arraycopy(_entries, 0, array, 0, array.length);
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an <b>immutable</b> view of this distributed set as a Java set.
|
||||
*/
|
||||
public Set<E> asSet ()
|
||||
{
|
||||
return new AbstractSet<E>() {
|
||||
@Override public boolean add (E o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override public boolean remove (Object o) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override public boolean contains (Object o) {
|
||||
if (!(o instanceof DSet.Entry)) {
|
||||
return false;
|
||||
}
|
||||
@SuppressWarnings("unchecked") E elem = (E)o;
|
||||
return DSet.this.contains(elem);
|
||||
}
|
||||
@Override public Iterator<E> iterator () {
|
||||
return DSet.this.iterator();
|
||||
}
|
||||
@Override public int size () {
|
||||
return DSet.this.size();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #toArray(Entry[])}.
|
||||
*/
|
||||
@Deprecated
|
||||
public Object[] toArray (Object[] array)
|
||||
{
|
||||
@SuppressWarnings("unchecked") E[] casted = (E[])array;
|
||||
return toArray(casted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified entry to the set. This should not be called directly, instead the
|
||||
* associated <code>addTo{Set}()</code> method should be called on the distributed object that
|
||||
* contains the set in question.
|
||||
*
|
||||
* @return true if the entry was added, false if it was already in the set.
|
||||
*/
|
||||
protected boolean add (E elem)
|
||||
{
|
||||
// determine where we'll be adding the new element
|
||||
int eidx = ArrayUtil.binarySearch(_entries, 0, _size, elem, ENTRY_COMP);
|
||||
|
||||
// if the element is already in the set, bail now
|
||||
if (eidx >= 0) {
|
||||
log.warning("Refusing to add duplicate entry", "entry", elem, "set", this,
|
||||
new Exception());
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert the index into happy positive land
|
||||
eidx = (eidx+1)*-1;
|
||||
|
||||
// expand our entries array if necessary
|
||||
int elength = _entries.length;
|
||||
if (_size >= elength) {
|
||||
// sanity check
|
||||
if (elength > getWarningSize()) {
|
||||
log.warning("Requested to expand to questionably large size", "l", elength,
|
||||
new Exception());
|
||||
}
|
||||
|
||||
// create a new array and copy our data into it
|
||||
@SuppressWarnings("unchecked") E[] elems = (E[])new Entry[elength*2];
|
||||
System.arraycopy(_entries, 0, elems, 0, elength);
|
||||
_entries = elems;
|
||||
}
|
||||
|
||||
// if the entry doesn't go at the end, shift the elements down to accomodate it
|
||||
if (eidx < _size) {
|
||||
System.arraycopy(_entries, eidx, _entries, eidx+1, _size-eidx);
|
||||
}
|
||||
|
||||
// stuff the entry into the array and note that we're bigger
|
||||
_entries[eidx] = elem;
|
||||
_size++;
|
||||
_modCount++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified entry from the set. This should not be called directly, instead the
|
||||
* associated <code>removeFrom{Set}()</code> method should be called on the distributed object
|
||||
* that contains the set in question.
|
||||
*
|
||||
* @return true if the entry was removed, false if it was not in the set.
|
||||
*/
|
||||
protected boolean remove (E elem)
|
||||
{
|
||||
return (null != removeKey(elem.getKey()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes from the set the entry whose key matches the supplied key. This should not be called
|
||||
* directly, instead the associated <code>removeFrom{Set}()</code> method should be called on
|
||||
* the distributed object that contains the set in question.
|
||||
*
|
||||
* @return the old matching entry if found and removed, null if not found.
|
||||
*/
|
||||
protected E removeKey (Comparable<?> key)
|
||||
{
|
||||
// don't fail, but generate a warning if we're passed a null key
|
||||
if (key == null) {
|
||||
log.warning("Requested to remove null key.", new Exception());
|
||||
return null;
|
||||
}
|
||||
|
||||
// look up this entry's position in our set
|
||||
int eidx = ArrayUtil.binarySearch(
|
||||
_entries, 0, _size, new SimpleEntry<Comparable<?>>(key), ENTRY_COMP);
|
||||
|
||||
// if we found it, remove it
|
||||
if (eidx >= 0) {
|
||||
// extract the old entry
|
||||
E oldEntry = _entries[eidx];
|
||||
_size--;
|
||||
if ((_entries.length > INITIAL_CAPACITY) && (_size < _entries.length/8)) {
|
||||
// if we're using less than 1/8 of our capacity, shrink by half
|
||||
@SuppressWarnings("unchecked") E[] newEnts = (E[])new Entry[_entries.length/2];
|
||||
System.arraycopy(_entries, 0, newEnts, 0, eidx);
|
||||
System.arraycopy(_entries, eidx+1, newEnts, eidx, _size-eidx);
|
||||
_entries = newEnts;
|
||||
|
||||
} else {
|
||||
// shift entries past the removed one downwards
|
||||
System.arraycopy(_entries, eidx+1, _entries, eidx, _size-eidx);
|
||||
_entries[_size] = null;
|
||||
}
|
||||
_modCount++;
|
||||
return oldEntry;
|
||||
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the specified entry by locating an entry whose key matches the key of the supplied
|
||||
* entry and overwriting it. This should not be called directly, instead the associated
|
||||
* <code>update{Set}()</code> method should be called on the distributed object that contains
|
||||
* the set in question.
|
||||
*
|
||||
* @return the old entry that was replaced, or null if it was not found (in which case nothing
|
||||
* is updated).
|
||||
*/
|
||||
protected E update (E elem)
|
||||
{
|
||||
// look up this entry's position in our set
|
||||
int eidx = ArrayUtil.binarySearch(_entries, 0, _size, elem, ENTRY_COMP);
|
||||
|
||||
// if we found it, update it
|
||||
if (eidx >= 0) {
|
||||
E oldEntry = _entries[eidx];
|
||||
_entries[eidx] = elem;
|
||||
_modCount++;
|
||||
return oldEntry;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum size where we should warn that we're getting a bit large.
|
||||
*/
|
||||
protected int getWarningSize ()
|
||||
{
|
||||
return 2048;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a shallow copy of this object in a type safe manner.
|
||||
*
|
||||
* @deprecated clone() works just fine now.
|
||||
*/
|
||||
@Deprecated
|
||||
public DSet<E> typedClone ()
|
||||
{
|
||||
return clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a shallow copy of this object.
|
||||
*/
|
||||
@Override
|
||||
public DSet<E> clone ()
|
||||
{
|
||||
try {
|
||||
@SuppressWarnings("unchecked") DSet<E> nset = (DSet<E>)super.clone();
|
||||
@SuppressWarnings("unchecked") E[] copy = (E[])new Entry[_entries.length];
|
||||
nset._entries = copy;
|
||||
System.arraycopy(_entries, 0, nset._entries, 0, _entries.length);
|
||||
nset._modCount = 0;
|
||||
return nset;
|
||||
} catch (CloneNotSupportedException cnse) {
|
||||
throw new AssertionError(cnse);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder("(");
|
||||
String prefix = "";
|
||||
for (E elem : _entries) {
|
||||
if (elem != null) {
|
||||
buf.append(prefix);
|
||||
prefix = ", ";
|
||||
buf.append(elem);
|
||||
}
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** Custom writer method. @see Streamable. */
|
||||
public void writeObject (ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeInt(_size);
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
out.writeObject(_entries[ii]);
|
||||
}
|
||||
}
|
||||
|
||||
/** Custom reader method. @see Streamable. */
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
_size = in.readInt();
|
||||
// ensure our capacity is a power of 2 (for consistency)
|
||||
int capacity = INITIAL_CAPACITY;
|
||||
while (capacity < _size) {
|
||||
capacity <<= 1;
|
||||
}
|
||||
@SuppressWarnings("unchecked") E[] entries = (E[])new Entry[capacity];
|
||||
_entries = entries;
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
@SuppressWarnings("unchecked") E entry = (E)in.readObject();
|
||||
_entries[ii] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
/** The entries of the set (in a sparse array). */
|
||||
@SuppressWarnings("unchecked") protected E[] _entries = (E[])new Entry[INITIAL_CAPACITY];
|
||||
|
||||
/** The number of entries in this set. */
|
||||
protected int _size;
|
||||
|
||||
/** Used to check for concurrent modification. */
|
||||
protected transient int _modCount;
|
||||
|
||||
/** The default capacity of a set instance. */
|
||||
protected static final int INITIAL_CAPACITY = 2;
|
||||
|
||||
/** Used for lookups and to keep the set contents sorted on insertions. */
|
||||
protected static Comparator<Entry> ENTRY_COMP = new Comparator<Entry>() {
|
||||
public int compare (Entry e1, Entry e2) {
|
||||
return DSet.compare(e1.getKey(), e2.getKey());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,145 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import com.samskivert.util.MethodFinder;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Maps distributed object events to methods using reflection.
|
||||
*/
|
||||
public class DynamicListener<T extends DSet.Entry>
|
||||
implements AttributeChangeListener, ElementUpdateListener, SetListener<T>
|
||||
{
|
||||
/**
|
||||
* Creates a listener that dynamically dispatches events on the supplied
|
||||
* target.
|
||||
*/
|
||||
public DynamicListener (Object target)
|
||||
{
|
||||
this(target, new MethodFinder(target.getClass()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a listener that dynamically dispatches events on the supplied
|
||||
* target using the methods in finder.
|
||||
*/
|
||||
public DynamicListener (Object target, MethodFinder finder)
|
||||
{
|
||||
_target = target;
|
||||
_finder = finder;
|
||||
}
|
||||
|
||||
// from interface AttributeChangeListener
|
||||
public void attributeChanged (AttributeChangedEvent event)
|
||||
{
|
||||
dispatchMethod(event.getName() + "Changed",
|
||||
new Object[] { event.getValue() });
|
||||
}
|
||||
|
||||
// from interface ElementUpdateListener
|
||||
public void elementUpdated (ElementUpdatedEvent event)
|
||||
{
|
||||
dispatchMethod(event.getName() + "Updated",
|
||||
new Object[] { event.getIndex(), event.getValue() });
|
||||
}
|
||||
|
||||
// from interface SetListener
|
||||
public void entryAdded (EntryAddedEvent<T> event)
|
||||
{
|
||||
dispatchMethod(event.getName() + "Added",
|
||||
new Object[] { event.getEntry() });
|
||||
}
|
||||
|
||||
// from interface SetListener
|
||||
public void entryUpdated (EntryUpdatedEvent<T> event)
|
||||
{
|
||||
dispatchMethod(event.getName() + "Updated",
|
||||
new Object[] { event.getEntry() });
|
||||
}
|
||||
|
||||
// from interface SetListener
|
||||
public void entryRemoved (EntryRemovedEvent<T> event)
|
||||
{
|
||||
dispatchMethod(event.getName() + "Removed",
|
||||
new Object[] { event.getKey() });
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically looks up the method in question on our target and dispatches
|
||||
* an event if it does.
|
||||
*/
|
||||
public void dispatchMethod (String name, Object[] arguments)
|
||||
{
|
||||
// first check the cache
|
||||
Method method = _mcache.get(name);
|
||||
if (method == null) {
|
||||
// if we haven't already determined this method doesn't exist, try
|
||||
// to resolve it
|
||||
if (!_mcache.containsKey(name)) {
|
||||
_mcache.put(name, method = resolveMethod(name, arguments));
|
||||
}
|
||||
}
|
||||
if (method != null) {
|
||||
try {
|
||||
method.invoke(_target, arguments);
|
||||
} catch (Exception e) {
|
||||
log.warning("Failed to dispatch event callback " +
|
||||
name + "(" + StringUtil.toString(arguments) + ").", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a method that matches the supplied signature.
|
||||
*/
|
||||
protected Method resolveMethod (String name, Object[] arguments)
|
||||
{
|
||||
Class<?>[] ptypes = new Class<?>[arguments.length];
|
||||
for (int ii = 0; ii < arguments.length; ii++) {
|
||||
ptypes[ii] = arguments[ii] == null ?
|
||||
null : arguments[ii].getClass();
|
||||
}
|
||||
try {
|
||||
return _finder.findMethod(name, ptypes);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** The object on which we will dynamically dispatch events. */
|
||||
protected Object _target;
|
||||
|
||||
/** Used to look up methods. */
|
||||
protected MethodFinder _finder;
|
||||
|
||||
/** A cache of already resolved methods. */
|
||||
protected HashMap<String, Method> _mcache = Maps.newHashMap();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about element updates that take place for a
|
||||
* particular distributed object.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface ElementUpdateListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when an element updated event has been dispatched on an object. This will be called
|
||||
* <em>after</em> the event has been applied to the object. So fetching the element during
|
||||
* this call will provide the new value for the element.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void elementUpdated (ElementUpdatedEvent event);
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* An element updated event is dispatched when an element of an array field in a distributed object
|
||||
* is updated. It can also be constructed to request the update of an entry and posted to the
|
||||
* dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class ElementUpdatedEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new element updated event on the specified target object with the supplied
|
||||
* attribute name, element and index.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has changed.
|
||||
* @param name the name of the attribute (data member) for which an element has changed.
|
||||
* @param value the new value of the element (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
* @param ovalue the previous value of the element (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
* @param index the index in the array of the updated element.
|
||||
*/
|
||||
public ElementUpdatedEvent (int targetOid, String name, Object value, Object ovalue, int index)
|
||||
{
|
||||
this(targetOid, name, value, ovalue, index, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new element updated event on the specified target object with the supplied
|
||||
* attribute name, element and index.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has changed.
|
||||
* @param name the name of the attribute (data member) for which an element has changed.
|
||||
* @param value the new value of the element (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
* @param ovalue the previous value of the element (in the case of primitive types, the
|
||||
* reflection-defined object-alternative is used).
|
||||
* @param index the index in the array of the updated element.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public ElementUpdatedEvent (
|
||||
int targetOid, String name, Object value, Object ovalue, int index, Transport transport)
|
||||
{
|
||||
super(targetOid, name, transport);
|
||||
_value = value;
|
||||
_oldValue = ovalue;
|
||||
_index = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for unserialization from the
|
||||
* network.
|
||||
*/
|
||||
public ElementUpdatedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element.
|
||||
*/
|
||||
public Object getValue ()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the element prior to the application of this event.
|
||||
*/
|
||||
public Object getOldValue ()
|
||||
{
|
||||
return _oldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the element.
|
||||
*/
|
||||
public int getIndex ()
|
||||
{
|
||||
return _index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element as a short. This will fail if the element in question
|
||||
* is not a short.
|
||||
*/
|
||||
public short getShortValue ()
|
||||
{
|
||||
return ((Short)_value).shortValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element as an int. This will fail if the element in question is
|
||||
* not an int.
|
||||
*/
|
||||
public int getIntValue ()
|
||||
{
|
||||
return ((Integer)_value).intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element as a long. This will fail if the element in question is
|
||||
* not a long.
|
||||
*/
|
||||
public long getLongValue ()
|
||||
{
|
||||
return ((Long)_value).longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element as a float. This will fail if the element in question
|
||||
* is not a float.
|
||||
*/
|
||||
public float getFloatValue ()
|
||||
{
|
||||
return ((Float)_value).floatValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new value of the element as a double. This will fail if the element in question
|
||||
* is not a double.
|
||||
*/
|
||||
public double getDoubleValue ()
|
||||
{
|
||||
return ((Double)_value).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
return (_oldValue != UNSET_OLD_VALUE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
if (!alreadyApplied()) {
|
||||
try {
|
||||
// fetch the array field from the object
|
||||
Field field = target.getClass().getField(_name);
|
||||
Class<?> ftype = field.getType();
|
||||
|
||||
// sanity check
|
||||
if (!ftype.isArray()) {
|
||||
String msg = "Requested to set element on non-array field.";
|
||||
throw new Exception(msg);
|
||||
}
|
||||
|
||||
// grab the previous value to provide to interested parties
|
||||
_oldValue = Array.get(field.get(target), _index);
|
||||
|
||||
// we don't do any magical expansion or any funny business; the array should be big
|
||||
// enough to contain the value being updated or we'll throw an
|
||||
// ArrayIndexOutOfBoundsException
|
||||
Array.set(field.get(target), _index, _value);
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error updating element [field=" + _name + ", index=" + _index + "]";
|
||||
throw new ObjectAccessException(msg, e);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof ElementUpdateListener) {
|
||||
((ElementUpdateListener)listener).elementUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("UPDATE:");
|
||||
super.toString(buf);
|
||||
buf.append(", value=");
|
||||
StringUtil.toString(buf, _value);
|
||||
buf.append(", index=").append(_index);
|
||||
}
|
||||
|
||||
protected Object _value;
|
||||
protected int _index;
|
||||
protected transient Object _oldValue = UNSET_OLD_VALUE;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* An entry added event is dispatched when an entry is added to a {@link DSet} attribute of a
|
||||
* distributed entry. It can also be constructed to request the addition of an entry to a set and
|
||||
* posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*
|
||||
* @param <T> the type of entry being handled by this event. This must match the type on the set
|
||||
* that generated this event.
|
||||
*/
|
||||
public class EntryAddedEvent<T extends DSet.Entry> extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new entry added event on the specified target object with the supplied set
|
||||
* attribute name and entry to add.
|
||||
*
|
||||
* @param targetOid the object id of the object to whose set we will add an entry.
|
||||
* @param name the name of the attribute to which to add the specified entry.
|
||||
* @param entry the entry to add to the set attribute.
|
||||
*/
|
||||
public EntryAddedEvent (int targetOid, String name, T entry)
|
||||
{
|
||||
this(targetOid, name, entry, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when the distributed object already added the entry before generating the event.
|
||||
*/
|
||||
public EntryAddedEvent (int targetOid, String name, T entry, boolean alreadyApplied)
|
||||
{
|
||||
super(targetOid, name);
|
||||
_entry = entry;
|
||||
_alreadyApplied = alreadyApplied;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for unserialization from the
|
||||
* network.
|
||||
*/
|
||||
public EntryAddedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry that has been added.
|
||||
*/
|
||||
public T getEntry ()
|
||||
{
|
||||
return _entry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
return _alreadyApplied;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
if (!_alreadyApplied) {
|
||||
if (!target.getSet(_name).add(_entry)) {
|
||||
return false; // DSet will have already complained
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof SetListener<?>) {
|
||||
@SuppressWarnings("unchecked") SetListener<T> setlist = (SetListener<T>)listener;
|
||||
setlist.entryAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("ELADD:");
|
||||
super.toString(buf);
|
||||
buf.append(", entry=");
|
||||
StringUtil.toString(buf, _entry);
|
||||
}
|
||||
|
||||
protected T _entry;
|
||||
|
||||
/** Used when this event is generated on the authoritative server where object changes are made
|
||||
* immediately. This lets us know not to apply ourselves when we're actually dispatched. */
|
||||
protected transient boolean _alreadyApplied;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* An entry removed event is dispatched when an entry is removed from a {@link DSet} attribute of a
|
||||
* distributed object. It can also be constructed to request the removal of an entry from a set and
|
||||
* posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*
|
||||
* @param <T> the type of entry being handled by this event. This must match the type on the set
|
||||
* that generated this event.
|
||||
*/
|
||||
public class EntryRemovedEvent<T extends DSet.Entry> extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new entry removed event on the specified target object with the supplied set
|
||||
* attribute name and entry key to remove.
|
||||
*
|
||||
* @param targetOid the object id of the object from whose set we will remove an entry.
|
||||
* @param name the name of the attribute from which to remove the specified entry.
|
||||
* @param key the entry key that identifies the entry to remove.
|
||||
* @param oldEntry the previous value of the entry.
|
||||
*/
|
||||
public EntryRemovedEvent (int targetOid, String name, Comparable<?> key, T oldEntry)
|
||||
{
|
||||
super(targetOid, name);
|
||||
_key = key;
|
||||
_oldEntry = oldEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for unserialization from the
|
||||
* network.
|
||||
*/
|
||||
public EntryRemovedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key that identifies the entry that has been removed.
|
||||
*/
|
||||
public Comparable<?> getKey ()
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry that was in the set prior to being updated.
|
||||
*/
|
||||
public T getOldEntry ()
|
||||
{
|
||||
return _oldEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
return (_oldEntry != UNSET_OLD_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
if (!alreadyApplied()) {
|
||||
DSet<T> set = target.getSet(_name);
|
||||
// remove, fetch the previous value for interested callers
|
||||
_oldEntry = set.removeKey(_key);
|
||||
if (_oldEntry == null) {
|
||||
// complain if there was actually nothing there
|
||||
log.warning("No matching entry to remove", "key", _key, "set", set);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof SetListener<?>) {
|
||||
@SuppressWarnings("unchecked") SetListener<T> setlist = (SetListener<T>)listener;
|
||||
setlist.entryRemoved(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("ELREM:");
|
||||
super.toString(buf);
|
||||
buf.append(", key=").append(_key);
|
||||
}
|
||||
|
||||
protected Comparable<?> _key;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* An entry updated event is dispatched when an entry of a {@link DSet} is updated. It can also be
|
||||
* constructed to request the update of an entry and posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*
|
||||
* @param <T> the type of entry being handled by this event. This must match the type on the set
|
||||
* that generated this event.
|
||||
*/
|
||||
public class EntryUpdatedEvent<T extends DSet.Entry> extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new entry updated event on the specified target object for the specified set
|
||||
* name and with the supplied updated entry.
|
||||
*
|
||||
* @param targetOid the object id of the object to whose set we will add an entry.
|
||||
* @param name the name of the attribute in which to update the specified entry.
|
||||
* @param entry the entry to update.
|
||||
* @param oldEntry the previous value of the entry.
|
||||
*/
|
||||
public EntryUpdatedEvent (int targetOid, String name, T entry, T oldEntry)
|
||||
{
|
||||
this(targetOid, name, entry, oldEntry, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new entry updated event on the specified target object for the specified set
|
||||
* name and with the supplied updated entry.
|
||||
*
|
||||
* @param targetOid the object id of the object to whose set we will add an entry.
|
||||
* @param name the name of the attribute in which to update the specified entry.
|
||||
* @param entry the entry to update.
|
||||
* @param oldEntry the previous value of the entry.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public EntryUpdatedEvent (int targetOid, String name, T entry, T oldEntry, Transport transport)
|
||||
{
|
||||
super(targetOid, name, transport);
|
||||
_entry = entry;
|
||||
_oldEntry = oldEntry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for unserialization from the
|
||||
* network.
|
||||
*/
|
||||
public EntryUpdatedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry that has been updated.
|
||||
*/
|
||||
public T getEntry ()
|
||||
{
|
||||
return _entry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the entry that was in the set prior to being updated.
|
||||
*/
|
||||
public T getOldEntry ()
|
||||
{
|
||||
return _oldEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean alreadyApplied ()
|
||||
{
|
||||
return (_oldEntry != UNSET_OLD_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// only apply the change if we haven't already
|
||||
if (!alreadyApplied()) {
|
||||
DSet<T> set = target.getSet(_name);
|
||||
// fetch the previous value for interested callers
|
||||
_oldEntry = set.update(_entry);
|
||||
if (_oldEntry == null) {
|
||||
// complain if we didn't update anything
|
||||
log.warning("No matching entry to update", "entry", this, "set", set);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof SetListener<?>) {
|
||||
@SuppressWarnings("unchecked") SetListener<T> setlist = (SetListener<T>)listener;
|
||||
setlist.entryUpdated(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("ELUPD:");
|
||||
super.toString(buf);
|
||||
buf.append(", entry=");
|
||||
StringUtil.toString(buf, _entry);
|
||||
}
|
||||
|
||||
protected T _entry;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected transient T _oldEntry = (T)UNSET_OLD_ENTRY;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about all events being dispatched on a particular
|
||||
* distributed object.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface EventListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when any event has been dispatched on an object. The event will be of the derived
|
||||
* class that corresponds to the kind of event that occurred on the object. This will be
|
||||
* called <em>after</em> the event has been applied to the object. So fetching an attribute
|
||||
* upon receiving an attribute changed event will provide the new value for the attribute.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void eventReceived (DEvent event);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* Used to dispatch an invocation notification from the server to a
|
||||
* client.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class InvocationNotificationEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new invocation notification event on the specified
|
||||
* target object with the supplied receiver id, method id and
|
||||
* arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param receiverId identifies the receiver to which this notification
|
||||
* is being dispatched.
|
||||
* @param methodId the id of the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
*/
|
||||
public InvocationNotificationEvent (
|
||||
int targetOid, short receiverId, int methodId, Object[] args)
|
||||
{
|
||||
this(targetOid, receiverId, methodId, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new invocation notification event on the specified
|
||||
* target object with the supplied receiver id, method id and
|
||||
* arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param receiverId identifies the receiver to which this notification
|
||||
* is being dispatched.
|
||||
* @param methodId the id of the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public InvocationNotificationEvent (
|
||||
int targetOid, short receiverId, int methodId, Object[] args, Transport transport)
|
||||
{
|
||||
super(targetOid, transport);
|
||||
_receiverId = receiverId;
|
||||
_methodId = (byte)methodId;
|
||||
_args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public InvocationNotificationEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the receiver id associated with this notification.
|
||||
*/
|
||||
public int getReceiverId ()
|
||||
{
|
||||
return _receiverId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the method associated with this notification.
|
||||
*/
|
||||
public int getMethodId ()
|
||||
{
|
||||
return _methodId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments associated with this notification.
|
||||
*/
|
||||
public Object[] getArgs ()
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("INOT:");
|
||||
super.toString(buf);
|
||||
buf.append(", rcvId=").append(_receiverId);
|
||||
buf.append(", methodId=").append(_methodId);
|
||||
buf.append(", args=").append(StringUtil.toString(_args));
|
||||
}
|
||||
|
||||
/** Identifies the receiver to which this notification is being
|
||||
* dispatched. */
|
||||
protected short _receiverId;
|
||||
|
||||
/** The id of the receiver method being invoked. */
|
||||
protected byte _methodId;
|
||||
|
||||
/** The arguments to the receiver method being invoked. */
|
||||
protected Object[] _args;
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* Used to dispatch an invocation request from the client to the server.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class InvocationRequestEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new invocation request event on the specified target
|
||||
* object with the supplied code, method and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param invCode the invocation provider identification code.
|
||||
* @param methodId the id of the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
*/
|
||||
public InvocationRequestEvent (
|
||||
int targetOid, int invCode, int methodId, Object[] args)
|
||||
{
|
||||
this(targetOid, invCode, methodId, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new invocation request event on the specified target
|
||||
* object with the supplied code, method and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param invCode the invocation provider identification code.
|
||||
* @param methodId the id of the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public InvocationRequestEvent (
|
||||
int targetOid, int invCode, int methodId, Object[] args, Transport transport)
|
||||
{
|
||||
super(targetOid, transport);
|
||||
_invCode = invCode;
|
||||
_methodId = (byte)methodId;
|
||||
_args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public InvocationRequestEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation code associated with this request.
|
||||
*/
|
||||
public int getInvCode ()
|
||||
{
|
||||
return _invCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the method associated with this request.
|
||||
*/
|
||||
public int getMethodId ()
|
||||
{
|
||||
return _methodId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments associated with this request.
|
||||
*/
|
||||
public Object[] getArgs ()
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("IREQ:");
|
||||
super.toString(buf);
|
||||
buf.append(", code=").append(_invCode);
|
||||
buf.append(", methodId=").append(_methodId);
|
||||
buf.append(", args=").append(StringUtil.toString(_args));
|
||||
}
|
||||
|
||||
/** The code identifying which invocation provider to which this
|
||||
* request is directed. */
|
||||
protected int _invCode;
|
||||
|
||||
/** The id of the method being invoked. */
|
||||
protected byte _methodId;
|
||||
|
||||
/** The arguments to the method being invoked. */
|
||||
protected Object[] _args;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* Used to dispatch an invocation response from the server to the client.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class InvocationResponseEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new invocation response event on the specified target
|
||||
* object with the supplied code, method and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param requestId the id of the request to which we are responding.
|
||||
* @param methodId the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
*/
|
||||
public InvocationResponseEvent (
|
||||
int targetOid, int requestId, int methodId, Object[] args)
|
||||
{
|
||||
this(targetOid, requestId, methodId, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new invocation response event on the specified target
|
||||
* object with the supplied code, method and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object on which the event is
|
||||
* to be dispatched.
|
||||
* @param requestId the id of the request to which we are responding.
|
||||
* @param methodId the method to be invoked.
|
||||
* @param args the arguments for the method. This array should contain
|
||||
* only values of valid distributed object types.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public InvocationResponseEvent (
|
||||
int targetOid, int requestId, int methodId, Object[] args, Transport transport)
|
||||
{
|
||||
super(targetOid, transport);
|
||||
_requestId = (short)requestId;
|
||||
_methodId = (byte)methodId;
|
||||
_args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public InvocationResponseEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the invocation request id associated with this response.
|
||||
*/
|
||||
public int getRequestId ()
|
||||
{
|
||||
return _requestId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the method associated with this response.
|
||||
*/
|
||||
public int getMethodId ()
|
||||
{
|
||||
return _methodId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments associated with this response.
|
||||
*/
|
||||
public Object[] getArgs ()
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
// nothing to do here
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("IRSP:");
|
||||
super.toString(buf);
|
||||
buf.append(", reqid=").append(_requestId);
|
||||
buf.append(", methodId=").append(_methodId);
|
||||
buf.append(", args=").append(StringUtil.toString(_args));
|
||||
}
|
||||
|
||||
/** The id of the request with which this response is associated. */
|
||||
protected short _requestId;
|
||||
|
||||
/** The id of the method being invoked. */
|
||||
protected byte _methodId;
|
||||
|
||||
/** The arguments to the method being invoked. */
|
||||
protected Object[] _args;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* A message event is used to dispatch a message to all subscribers of a
|
||||
* distributed object without actually changing any of the fields of the
|
||||
* object. A message has a name, by which different subscribers of the
|
||||
* same object can distinguish their different messages, and an array of
|
||||
* arguments by which any contents of the message can be delivered.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class MessageEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new message event on the specified target object with
|
||||
* the supplied name and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has
|
||||
* changed.
|
||||
* @param name the name of the message event.
|
||||
* @param args the arguments for this message. This array should
|
||||
* contain only values of valid distributed object types.
|
||||
*/
|
||||
public MessageEvent (int targetOid, String name, Object[] args)
|
||||
{
|
||||
this(targetOid, name, args, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new message event on the specified target object with
|
||||
* the supplied name and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has
|
||||
* changed.
|
||||
* @param name the name of the message event.
|
||||
* @param args the arguments for this message. This array should
|
||||
* contain only values of valid distributed object types.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public MessageEvent (int targetOid, String name, Object[] args, Transport transport)
|
||||
{
|
||||
super(targetOid, name, transport);
|
||||
_args = args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public MessageEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arguments to this message.
|
||||
*/
|
||||
public Object[] getArgs ()
|
||||
{
|
||||
return _args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the arguments associated with this message event.
|
||||
* <em>Note:</em> this should only be called on events that have not
|
||||
* yet been dispatched into the distributed object system.
|
||||
*/
|
||||
public void setArgs (Object[] args)
|
||||
{
|
||||
_args = args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to do here
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof MessageListener) {
|
||||
((MessageListener)listener).messageReceived(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("MSG:");
|
||||
super.toString(buf);
|
||||
buf.append(", args=").append(StringUtil.toString(_args));
|
||||
}
|
||||
|
||||
protected Object[] _args;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about message events that are dispatched on a
|
||||
* particular distributed object.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface MessageListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when an message event has been dispatched on an object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void messageReceived (MessageEvent event);
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.presents.dobj.AttributeChangeListener;
|
||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||
|
||||
/**
|
||||
* A AttributeChangeListener that listens for changes with a given name and calls
|
||||
* <code>namedAttributeChanged</code> when they occur.
|
||||
*/
|
||||
public abstract class NamedAttributeListener
|
||||
implements AttributeChangeListener
|
||||
{
|
||||
/**
|
||||
* Listen for AttributeChangedEvent events with the given name.
|
||||
*/
|
||||
public NamedAttributeListener (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
final public void attributeChanged (AttributeChangedEvent event)
|
||||
{
|
||||
if (event.getName().equals(_name)) {
|
||||
namedAttributeChanged(event);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The attribute this listener is watching has changed.
|
||||
*/
|
||||
public abstract void namedAttributeChanged (AttributeChangedEvent event);
|
||||
|
||||
protected final String _name;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* An ElementUpdateListener that listens for changes with a given name and calls
|
||||
* namedElementUpdated when they occur.
|
||||
*/
|
||||
public abstract class NamedElementUpdateListener
|
||||
implements ElementUpdateListener
|
||||
{
|
||||
/**
|
||||
* Listen for element updates with the given name.
|
||||
*/
|
||||
public NamedElementUpdateListener (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
final public void elementUpdated (ElementUpdatedEvent event)
|
||||
{
|
||||
if (event.getName().equals(_name)) {
|
||||
namedElementUpdated(event);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected void namedElementUpdated (ElementUpdatedEvent event);
|
||||
|
||||
protected final String _name;
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.presents.net.Transport;
|
||||
|
||||
/**
|
||||
* A common parent class for all events that are associated with a name
|
||||
* (in some cases a field name, in other cases just an identifying name).
|
||||
*/
|
||||
public abstract class NamedEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new named event for the specified target object with
|
||||
* the supplied attribute name.
|
||||
*
|
||||
* @param targetOid the object id of the object in question.
|
||||
* @param name the name associated with this event.
|
||||
*/
|
||||
public NamedEvent (int targetOid, String name)
|
||||
{
|
||||
this(targetOid, name, Transport.DEFAULT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new named event for the specified target object with
|
||||
* the supplied attribute name.
|
||||
*
|
||||
* @param targetOid the object id of the object in question.
|
||||
* @param name the name associated with this event.
|
||||
* @param transport a hint as to the type of transport desired for the event.
|
||||
*/
|
||||
public NamedEvent (int targetOid, String name, Transport transport)
|
||||
{
|
||||
super(targetOid, transport);
|
||||
_name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public NamedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the attribute to which this event pertains.
|
||||
*/
|
||||
public String getName ()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
super.toString(buf);
|
||||
buf.append(", name=").append(_name);
|
||||
}
|
||||
|
||||
protected String _name;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* A SetAdapter that listens for changes with a given name and calls the 'named' version of the
|
||||
* SetListener methods when they occur.
|
||||
*/
|
||||
public class NamedSetAdapter<T extends DSet.Entry> extends SetAdapter<T>
|
||||
{
|
||||
/**
|
||||
* Listen for DSet events with the given name.
|
||||
*/
|
||||
public NamedSetAdapter (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void entryAdded (EntryAddedEvent<T> event)
|
||||
{
|
||||
if (event.getName().equals(_name)) {
|
||||
namedEntryAdded(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void namedEntryAdded (EntryAddedEvent<T> event)
|
||||
{
|
||||
// Override to provide functionality
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void entryRemoved (EntryRemovedEvent<T> event)
|
||||
{
|
||||
if (event.getName().equals(_name)) {
|
||||
namedEntryRemoved(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void namedEntryRemoved (EntryRemovedEvent<T> event)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
final public void entryUpdated (EntryUpdatedEvent<T> event)
|
||||
{
|
||||
if (event.getName().equals(_name)) {
|
||||
namedEntryUpdated(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void namedEntryUpdated (EntryUpdatedEvent<T> event)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected final String _name;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* A no such object exception is delivered when a subscriber requests
|
||||
* access to an object that does not exist.
|
||||
*/
|
||||
public class NoSuchObjectException extends ObjectAccessException
|
||||
{
|
||||
public NoSuchObjectException (int oid)
|
||||
{
|
||||
super("m.no_such_object\t" + oid);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* An object access exception is delivered when an object is not accessible to a requesting
|
||||
* subscriber for some reason or other. For some access exceptions, special derived classes exist
|
||||
* to communicate the error. For others, a message string explaining the access failure is
|
||||
* provided.
|
||||
*/
|
||||
public class ObjectAccessException extends Exception
|
||||
{
|
||||
/**
|
||||
* Constructs a object access exception with the specified error message.
|
||||
*/
|
||||
public ObjectAccessException (String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a object access exception with the specified error message and the chained
|
||||
* causing event.
|
||||
*/
|
||||
public ObjectAccessException (String message, Exception cause)
|
||||
{
|
||||
super(message);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a object access exception with the specified chained causing event.
|
||||
*/
|
||||
public ObjectAccessException (Exception cause)
|
||||
{
|
||||
initCause(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* An object added event is dispatched when an object is added to an
|
||||
* <code>OidList</code> attribute of a distributed object. It can also be
|
||||
* constructed to request the addition of an oid to an
|
||||
* <code>OidList</code> attribute of an object and posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class ObjectAddedEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new object added event on the specified target object
|
||||
* with the supplied oid list attribute name and object id to add.
|
||||
*
|
||||
* @param targetOid the object id of the object to whose oid list we
|
||||
* will add an oid.
|
||||
* @param name the name of the attribute (data member) to which to add
|
||||
* the specified oid.
|
||||
* @param oid the oid to add to the oid list attribute.
|
||||
*/
|
||||
public ObjectAddedEvent (int targetOid, String name, int oid)
|
||||
{
|
||||
super(targetOid, name);
|
||||
_oid = oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public ObjectAddedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid that has been added.
|
||||
*/
|
||||
public int getOid ()
|
||||
{
|
||||
return _oid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
OidList list = (OidList)target.getAttribute(_name);
|
||||
list.add(_oid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof OidListListener) {
|
||||
((OidListListener)listener).objectAdded(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("OBJADD:");
|
||||
super.toString(buf);
|
||||
buf.append(", oid=").append(_oid);
|
||||
}
|
||||
|
||||
protected int _oid;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about object destruction events.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface ObjectDeathListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when this object has been destroyed. This will be called <em>after</em> the event has
|
||||
* been applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void objectDestroyed (ObjectDestroyedEvent event);
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* An object destroyed event is dispatched when an object has been removed
|
||||
* from the distributed object system. It can also be constructed to
|
||||
* request an attribute change on an object and posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class ObjectDestroyedEvent extends DEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new object destroyed event for the specified
|
||||
* distributed object.
|
||||
*
|
||||
* @param targetOid the object id of the object that will be destroyed.
|
||||
*/
|
||||
public ObjectDestroyedEvent (int targetOid)
|
||||
{
|
||||
super(targetOid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public ObjectDestroyedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// nothing to do in preparation for destruction, the omgr will
|
||||
// have to recognize this type of event and do the right thing
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof ObjectDeathListener) {
|
||||
((ObjectDeathListener)listener).objectDestroyed(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("DESTROY:");
|
||||
super.toString(buf);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* An object removed event is dispatched when an object is removed from an
|
||||
* <code>OidList</code> attribute of a distributed object. It can also be
|
||||
* constructed to request the removal of an oid from an
|
||||
* <code>OidList</code> attribute of an object and posted to the dobjmgr.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class ObjectRemovedEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new object removed event on the specified target
|
||||
* object with the supplied oid list attribute name and object id to
|
||||
* remove.
|
||||
*
|
||||
* @param targetOid the object id of the object from whose oid list we
|
||||
* will remove an oid.
|
||||
* @param name the name of the attribute (data member) from which to
|
||||
* remove the specified oid.
|
||||
* @param oid the oid to remove from the oid list attribute.
|
||||
*/
|
||||
public ObjectRemovedEvent (int targetOid, String name, int oid)
|
||||
{
|
||||
super(targetOid, name);
|
||||
_oid = oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public ObjectRemovedEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid that has been removed.
|
||||
*/
|
||||
public int getOid ()
|
||||
{
|
||||
return _oid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
OidList list = (OidList)target.getAttribute(_name);
|
||||
list.remove(_oid);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyListener (Object listener)
|
||||
{
|
||||
if (listener instanceof OidListListener) {
|
||||
((OidListListener)listener).objectRemoved(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("OBJREM:");
|
||||
super.toString(buf);
|
||||
buf.append(", oid=").append(_oid);
|
||||
}
|
||||
|
||||
protected int _oid;
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
/**
|
||||
* An oid list is used to store lists of object ids. The list will not
|
||||
* allow duplicate ids. This class is not synchronized, with the
|
||||
* expectation that all modifications of instances will take place on the
|
||||
* dobjmgr thread.
|
||||
*
|
||||
* <ul>
|
||||
* <li> Do not use an OidList to store a set of ints. OidList has special meaning inside
|
||||
* of the dobj system, namely:
|
||||
* <li> When an object is destroyed, its oid is automagically removed from any OidLists.
|
||||
* </ul>
|
||||
*/
|
||||
public class OidList implements Streamable
|
||||
{
|
||||
/**
|
||||
* Creates an empty oid list.
|
||||
*/
|
||||
public OidList ()
|
||||
{
|
||||
this(DEFAULT_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty oid list with space for at least
|
||||
* <code>initialSize</code> object ids before it will need to expand.
|
||||
*/
|
||||
public OidList (int initialSize)
|
||||
{
|
||||
// ensure that we have at least two slots or the expansion code
|
||||
// won't work
|
||||
_oids = new int[Math.max(initialSize, 2)];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of object ids in the list.
|
||||
*/
|
||||
public int size ()
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified object id to the list if it is not already
|
||||
* there.
|
||||
*
|
||||
* @return true if the object was added, false if it was already in
|
||||
* the list.
|
||||
*/
|
||||
public boolean add (int oid)
|
||||
{
|
||||
// check for existence
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
if (_oids[ii] == oid) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// make room if necessary
|
||||
if (_size+1 >= _oids.length) {
|
||||
expand();
|
||||
}
|
||||
|
||||
// add the oid
|
||||
_oids[_size++] = oid;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the specified oid from the list.
|
||||
*
|
||||
* @return true if the oid was in the list and was removed, false
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean remove (int oid)
|
||||
{
|
||||
// scan for the oid in question
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
if (_oids[ii] == oid) {
|
||||
// shift the rest of the list back one
|
||||
System.arraycopy(_oids, ii+1, _oids, ii, --_size-ii);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified oid is in the list, false if not.
|
||||
*/
|
||||
public boolean contains (int oid)
|
||||
{
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
if (_oids[ii] == oid) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the object id at the specified index. This does no boundary
|
||||
* checking.
|
||||
*/
|
||||
public int get (int index)
|
||||
{
|
||||
return _oids[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("{");
|
||||
for (int ii = 0; ii < _size; ii++) {
|
||||
if (ii > 0) {
|
||||
buf.append(", ");
|
||||
}
|
||||
buf.append(_oids[ii]);
|
||||
}
|
||||
buf.append("}");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private void expand ()
|
||||
{
|
||||
int[] oids = new int[_oids.length*2];
|
||||
System.arraycopy(_oids, 0, oids, 0, _oids.length);
|
||||
_oids = oids;
|
||||
}
|
||||
|
||||
private int[] _oids;
|
||||
private int _size;
|
||||
|
||||
protected static final int DEFAULT_SIZE = 4;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about changes that occur to oid list attributes of a
|
||||
* particular distributed object.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface OidListListener extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when an object added event has been dispatched on an object. This will be called
|
||||
* <em>after</em> the event has been applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void objectAdded (ObjectAddedEvent event);
|
||||
|
||||
/**
|
||||
* Called when an object removed event has been dispatched on an object. This will be called
|
||||
* <em>after</em> the event has been applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void objectRemoved (ObjectRemovedEvent event);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.presents.data.ClientObject;
|
||||
|
||||
/**
|
||||
* Defines a special kind of subscriber that proxies events for a subordinate distributed object
|
||||
* manager. All events dispatched on objects with which this subscriber is registered are passed
|
||||
* along to the subscriber for delivery to its subordinate manager.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*/
|
||||
public interface ProxySubscriber extends Subscriber<DObject>
|
||||
{
|
||||
/**
|
||||
* Called when any event has been dispatched on an object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void eventReceived (DEvent event);
|
||||
|
||||
/**
|
||||
* Returns the client object that represents the subscriber for whom we are proxying.
|
||||
*/
|
||||
ClientObject getClientObject ();
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* A release lock event is dispatched at the end of a chain of events to
|
||||
* release a lock that is intended to prevent some application defined
|
||||
* activity from happening until those events have been processed. This is
|
||||
* an entirely cooperative locking system, meaning that the application
|
||||
* will have to explicitly attempt acquisition of the lock to find out if
|
||||
* the lock has yet been released. These locks don't actually prevent any
|
||||
* of the distributed object machinery from functioning.
|
||||
*
|
||||
* @see DObjectManager#postEvent
|
||||
*/
|
||||
public class ReleaseLockEvent extends NamedEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new release lock event for the specified target object
|
||||
* with the supplied lock name.
|
||||
*
|
||||
* @param targetOid the object id of the object in question.
|
||||
* @param name the name of the lock to release.
|
||||
*/
|
||||
public ReleaseLockEvent (int targetOid, String name)
|
||||
{
|
||||
super(targetOid, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank instance of this event in preparation for
|
||||
* unserialization from the network.
|
||||
*/
|
||||
public ReleaseLockEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrivate ()
|
||||
{
|
||||
// we need only run on the server; no need to propagate to proxies
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies this lock release to the object.
|
||||
*/
|
||||
@Override
|
||||
public boolean applyToObject (DObject target)
|
||||
throws ObjectAccessException
|
||||
{
|
||||
// clear this lock from the target object
|
||||
target.clearLock(_name);
|
||||
// no need to notify subscribers about these sorts of events
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void toString (StringBuilder buf)
|
||||
{
|
||||
buf.append("UNLOCK:");
|
||||
super.toString(buf);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import com.samskivert.util.Interval;
|
||||
import com.samskivert.util.RunQueue;
|
||||
|
||||
/**
|
||||
* The root distributed object manager extends the basic distributed object manager interface with
|
||||
* methods that can only be guaranteed to work in the virtual machine that is hosting the
|
||||
* distributed objects in question. VMs that operate proxies of objects can only implement the
|
||||
* basic distributed object manager interface.
|
||||
*/
|
||||
public interface RootDObjectManager extends DObjectManager, RunQueue, Executor
|
||||
{
|
||||
/**
|
||||
* Looks up and returns the requested distributed object in the dobj table, returning null if
|
||||
* no object exists with that oid.
|
||||
*/
|
||||
DObject getObject (int oid);
|
||||
|
||||
/**
|
||||
* Registers a distributed object instance of the supplied class with the system and assigns it
|
||||
* an oid. When the call returns the object will be registered with the system and its oid will
|
||||
* have been assigned.
|
||||
*
|
||||
* @return the registered object for the caller's convenience.
|
||||
*/
|
||||
<T extends DObject> T registerObject (T object);
|
||||
|
||||
/**
|
||||
* Requests that the specified object be destroyed. Once destroyed an object is removed from
|
||||
* the runtime system and may no longer have events dispatched on it.
|
||||
*
|
||||
* @param oid The object id of the distributed object to be destroyed.
|
||||
*/
|
||||
void destroyObject (int oid);
|
||||
|
||||
/**
|
||||
* Creates an {@link Interval} that runs the supplied runnable. If the root omgr is shutdown
|
||||
* before the interval expires (or if the interval is scheduled to repeat), it will be
|
||||
* automatically cancelled. This makes it easy to schedule fire-and-forget intervals:
|
||||
*
|
||||
* <pre>
|
||||
* _omgr.newInterval(someRunnable).schedule(500); // one shot
|
||||
* Interval ival = _omgr.newInterval(someRunnable).schedule(500, true); // repeater
|
||||
* </pre>
|
||||
*/
|
||||
Interval newInterval (Runnable action);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* A message event that only goes to the server. If generated on the server then it never leaves
|
||||
* the server.
|
||||
*/
|
||||
public class ServerMessageEvent extends MessageEvent
|
||||
{
|
||||
/**
|
||||
* Constructs a new message event on the specified target object with
|
||||
* the supplied name and arguments.
|
||||
*
|
||||
* @param targetOid the object id of the object whose attribute has
|
||||
* changed.
|
||||
* @param name the name of the message event.
|
||||
* @param args the arguments for this message. This array should
|
||||
* contain only values of valid distributed object types.
|
||||
*/
|
||||
public ServerMessageEvent (int targetOid, String name, Object[] args)
|
||||
{
|
||||
super(targetOid, name, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Suitable for unserialization.
|
||||
*/
|
||||
public ServerMessageEvent ()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrivate ()
|
||||
{
|
||||
// this is what makes us server-only
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implements the methods in SetListener so that you don't have to implement the ones you don't
|
||||
* want to.
|
||||
*
|
||||
* <p> <b>NOTE:</b> This adapter will receive <em>all</em> Entry events from a DObject it's
|
||||
* listening to, so it should check that the event's name matches the field it's interested in
|
||||
* before acting on the event.
|
||||
*
|
||||
* @param <T> the type of entry being handled by this listener. This must match the type on the set
|
||||
* that generates the events.
|
||||
*/
|
||||
public class SetAdapter<T extends DSet.Entry> implements SetListener<T>
|
||||
{
|
||||
// documentation inherited from interface SetListener
|
||||
public void entryAdded (EntryAddedEvent<T> event)
|
||||
{
|
||||
// override to provide functionality
|
||||
}
|
||||
|
||||
// documentation inherited from interface SetListener
|
||||
public void entryUpdated (EntryUpdatedEvent<T> event)
|
||||
{
|
||||
// override to provide functionality
|
||||
}
|
||||
|
||||
// documentation inherited from interface SetListener
|
||||
public void entryRemoved (EntryRemovedEvent<T> event)
|
||||
{
|
||||
// override to provide functionality
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* Implemented by entities which wish to hear about changes that occur to set attributes of a
|
||||
* particular distributed object.
|
||||
*
|
||||
* <p> <b>NOTE:</b> This listener will receive <em>all</em> Entry events from a DObject it's
|
||||
* listening to, so it should check that the event's name matches the field it's interested in
|
||||
* before acting on the event.
|
||||
*
|
||||
* @see DObject#addListener
|
||||
*
|
||||
* @param <T> the type of entry being handled by this listener. This must match the type on the set
|
||||
* that generates the events.
|
||||
*/
|
||||
public interface SetListener<T extends DSet.Entry> extends ChangeListener
|
||||
{
|
||||
/**
|
||||
* Called when an entry added event has been dispatched on an
|
||||
* object. This will be called <em>after</em> the event has been
|
||||
* applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void entryAdded (EntryAddedEvent<T> event);
|
||||
|
||||
/**
|
||||
* Called when an entry updated event has been dispatched on an
|
||||
* object. This will be called <em>after</em> the event has been
|
||||
* applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void entryUpdated (EntryUpdatedEvent<T> event);
|
||||
|
||||
/**
|
||||
* Called when an entry removed event has been dispatched on an
|
||||
* object. This will be called <em>after</em> the event has been
|
||||
* applied to the object.
|
||||
*
|
||||
* @param event The event that was dispatched on the object.
|
||||
*/
|
||||
void entryRemoved (EntryRemovedEvent<T> event);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
/**
|
||||
* A quick and easy DSet.Entry that holds some sort of Comparable.
|
||||
*
|
||||
* Remember: this type must also be {@link Streamable}.
|
||||
*/
|
||||
public class SimpleEntry<T extends Comparable<?>>
|
||||
implements DSet.Entry
|
||||
{
|
||||
// Zero arg constructor for unserialization
|
||||
public SimpleEntry () { }
|
||||
|
||||
public SimpleEntry (T key) {
|
||||
_key = key;
|
||||
}
|
||||
|
||||
public T getKey () {
|
||||
return _key;
|
||||
}
|
||||
|
||||
protected T _key;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.dobj;
|
||||
|
||||
/**
|
||||
* A subscriber is an entity that has access to a distributed object. The
|
||||
* process of obtaining access to a distributed object is an asynchronous
|
||||
* one, and changes made to an object are delivered asynchronously. By
|
||||
* registering as a subscriber to an object, an entity can react to
|
||||
* changes made to an object and ensure that their object is kept up to
|
||||
* date.
|
||||
*
|
||||
* <p> To actually receive callbacks when events are dispatched on a
|
||||
* distributed object, an entity should register itself as a listener on
|
||||
* the object once it has received its object reference.
|
||||
*
|
||||
* @see EventListener
|
||||
* @see AttributeChangeListener
|
||||
* @see SetListener
|
||||
* @see OidListListener
|
||||
*
|
||||
* @param <T> the type object being subscribed to.
|
||||
*/
|
||||
public interface Subscriber<T extends DObject>
|
||||
{
|
||||
/**
|
||||
* Called when a subscription request has succeeded and the object is
|
||||
* available. If the object was requested for subscription, the
|
||||
* subscriber can subsequently receive notifications by registering
|
||||
* itself as a listener of some sort (see {@link
|
||||
* DObject#addListener}).
|
||||
*
|
||||
* @see DObjectManager#subscribeToObject
|
||||
*/
|
||||
void objectAvailable (T object);
|
||||
|
||||
/**
|
||||
* Called when a subscription request has failed. The nature of the
|
||||
* failure will be communicated via the supplied
|
||||
* <code>ObjectAccessException</code>.
|
||||
*
|
||||
* @see DObjectManager#subscribeToObject
|
||||
*/
|
||||
void requestFailed (int oid, ObjectAccessException cause);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import java.util.TimeZone;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
|
||||
/**
|
||||
* Used to authenticate with the server.
|
||||
*/
|
||||
public class AuthRequest extends UpstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public AuthRequest ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a auth request with the supplied credentials and client version information.
|
||||
*/
|
||||
public AuthRequest (Credentials creds, String version, String[] bootGroups)
|
||||
{
|
||||
_creds = creds;
|
||||
_version = version;
|
||||
_zone = TimeZone.getDefault().getID();
|
||||
_bootGroups = bootGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the credentials provided with this request.
|
||||
*/
|
||||
public Credentials getCredentials ()
|
||||
{
|
||||
return _creds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the version information provided with this request.
|
||||
*/
|
||||
public String getVersion ()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the timezone in which this client is operating.
|
||||
*/
|
||||
public TimeZone getTimeZone ()
|
||||
{
|
||||
return TimeZone.getTimeZone(_zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of bootstrap service groups in which this client is interested.
|
||||
*/
|
||||
public String[] getBootGroups ()
|
||||
{
|
||||
return _bootGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=AREQ, msgid=" + messageId + ", creds=" + _creds +
|
||||
", version=" + _version + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads our custom streamable fields.
|
||||
*/
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
try {
|
||||
in.defaultReadObject();
|
||||
} catch (IOException ioe) {
|
||||
// if we fail here because the client is old, leave ourselves with a partially
|
||||
// initialized set of credentials, which the server will generally cope with by telling
|
||||
// the client it is out of date
|
||||
}
|
||||
}
|
||||
|
||||
/** The credentials associated with this auth request. */
|
||||
protected Credentials _creds;
|
||||
|
||||
/** The version information associated with the client code. */
|
||||
protected String _version;
|
||||
|
||||
/** The timezone in which this client is operating. */
|
||||
protected String _zone;
|
||||
|
||||
/** The set of bootstrap service groups this client is interested in. */
|
||||
protected String[] _bootGroups;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* The auth response communicates authentication success or failure as
|
||||
* well as associated information via a distribted object transmitted
|
||||
* along with the response. The distributed object simply serves as a
|
||||
* container for the varied and manifold data involved in the
|
||||
* authentication process.
|
||||
*/
|
||||
public class AuthResponse extends DownstreamMessage
|
||||
{
|
||||
/** Auxilliary authentication data to be communicated to the <code>
|
||||
* PresentsSession</code> once a session is started. This is a means by
|
||||
* which the <code>Authenticator</code> can pass information loaded from,
|
||||
* say, an authentication database into the runtime system to be used, for
|
||||
* example for permissions. */
|
||||
public transient Object authdata;
|
||||
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public AuthResponse ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a auth response with the supplied response data.
|
||||
*/
|
||||
public AuthResponse (AuthResponseData data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public AuthResponseData getData ()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces this response's auth data.
|
||||
*/
|
||||
public void setData (AuthResponseData data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=ARSP, msgid=" + messageId + ", data=" + _data + "]";
|
||||
}
|
||||
|
||||
protected AuthResponseData _data;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
|
||||
/**
|
||||
* An <code>AuthResponseData</code> object is communicated back to the
|
||||
* client along with an authentication response. It contains an indicator
|
||||
* of authentication success or failure along with bootstrap information
|
||||
* for the client.
|
||||
*/
|
||||
public class AuthResponseData extends DObject
|
||||
{
|
||||
/** The constant used to indicate a successful authentication. */
|
||||
public static final String SUCCESS = "success";
|
||||
|
||||
/**
|
||||
* Either the {@link #SUCCESS} constant or a reason code indicating
|
||||
* why the authentication failed.
|
||||
*/
|
||||
public String code;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
|
||||
import com.threerings.presents.data.InvocationMarshaller;
|
||||
|
||||
/**
|
||||
* A <code>BootstrapData</code> object is communicated back to the client after authentication has
|
||||
* succeeded and after the server is fully prepared to deal with the client. It contains
|
||||
* information the client will need to interact with the server.
|
||||
*/
|
||||
public class BootstrapData extends SimpleStreamableObject
|
||||
{
|
||||
/** The unique id of the client's connection (used to address datagrams). */
|
||||
public int connectionId;
|
||||
|
||||
/** The oid of this client's associated distributed object. */
|
||||
public int clientOid;
|
||||
|
||||
/** A list of handles to invocation services. */
|
||||
public List<InvocationMarshaller> services;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* A bootstrap notification is delivered to the client once the server has
|
||||
* fully initialized itself in preparation for dealing with this client.
|
||||
* The authentication process completes very early and further information
|
||||
* need be communicated to the client so that it can fully interact with
|
||||
* the server. This information is communicated via the bootstrap
|
||||
* notification.
|
||||
*/
|
||||
public class BootstrapNotification extends DownstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public BootstrapNotification ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an bootstrap notification with the supplied data.
|
||||
*/
|
||||
public BootstrapNotification (BootstrapData data)
|
||||
{
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public BootstrapData getData ()
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=BOOT, msgid=" + messageId + ", data=" + _data + "]";
|
||||
}
|
||||
|
||||
/** The data associated with this notification. */
|
||||
protected BootstrapData _data;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.io.Streamable;
|
||||
|
||||
/**
|
||||
* Credentials are supplied by the client implementation and sent along to the server during the
|
||||
* authentication process. To provide support for a variety of authentication methods, the
|
||||
* credentials class is meant to be subclassed for the particular method (ie. password, auth
|
||||
* digest, etc.) in use in a given system.
|
||||
*
|
||||
* <p> All derived classes should provide a no argument constructor so that they can be
|
||||
* instantiated prior to reconstruction from a data input stream.
|
||||
*/
|
||||
public abstract class Credentials implements Streamable
|
||||
{
|
||||
/**
|
||||
* Returns a string to use in a hash on the datagram contents to authenticate client datagrams.
|
||||
*/
|
||||
public String getDatagramSecret ()
|
||||
{
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* This class encapsulates a message in the distributed object protocol that flows from the server
|
||||
* to the client. Downstream messages include object subscription, event forwarding and session
|
||||
* management.
|
||||
*/
|
||||
public abstract class DownstreamMessage extends Message
|
||||
{
|
||||
/**
|
||||
* The message id of the upstream message with which this downstream message is associated (or
|
||||
* -1 if it is not associated with any upstream message).
|
||||
*/
|
||||
public short messageId = -1;
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[msgid=" + messageId + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.presents.dobj.DEvent;
|
||||
|
||||
/**
|
||||
* Contains an event forwarded from the server.
|
||||
*/
|
||||
public class EventNotification extends DownstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public EventNotification ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an event notification for the supplied event.
|
||||
*/
|
||||
public EventNotification (DEvent event)
|
||||
{
|
||||
_event = event;
|
||||
}
|
||||
|
||||
public DEvent getEvent ()
|
||||
{
|
||||
return _event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
// the event handles the transport
|
||||
_event.setTransport(transport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return _event.getTransport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void noteActualTransport (Transport transport)
|
||||
{
|
||||
_event.noteActualTransport(transport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=EVT, evt=" + _event + "]";
|
||||
}
|
||||
|
||||
/** The event which we are forwarding. */
|
||||
protected DEvent _event;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* Communicates failure to subscribe to an object.
|
||||
*/
|
||||
public class FailureResponse extends DownstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public FailureResponse ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a failure response in response to a request for the specified oid.
|
||||
*/
|
||||
public FailureResponse (int oid, String message)
|
||||
{
|
||||
_oid = oid;
|
||||
_message = message;
|
||||
}
|
||||
|
||||
public int getOid ()
|
||||
{
|
||||
return _oid;
|
||||
}
|
||||
|
||||
public String getMessage ()
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=FAIL, msgid=" + messageId + ", oid=" + _oid + ", msg=" + _message + "]";
|
||||
}
|
||||
|
||||
protected int _oid;
|
||||
protected String _message;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.presents.dobj.DEvent;
|
||||
|
||||
/**
|
||||
* Forwards an event to the server for dispatch.
|
||||
*/
|
||||
public class ForwardEventRequest extends UpstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public ForwardEventRequest ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a forward event request for the supplied event.
|
||||
*/
|
||||
public ForwardEventRequest (DEvent event)
|
||||
{
|
||||
_event = event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the event that we wish to have forwarded.
|
||||
*/
|
||||
public DEvent getEvent ()
|
||||
{
|
||||
return _event;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
// the event handles the transport
|
||||
_event.setTransport(transport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return _event.getTransport();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=FWD, evt=" + _event + "]";
|
||||
}
|
||||
|
||||
/** The event which we are forwarding. */
|
||||
protected DEvent _event;
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* Requests to end our session with the server.
|
||||
*/
|
||||
public class LogoffRequest extends UpstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public LogoffRequest ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=LOGOFF, msgid=" + messageId + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.io.SimpleStreamableObject;
|
||||
|
||||
/**
|
||||
* The superclass of {@link UpstreamMessage} and {@link DownstreamMessage}.
|
||||
*/
|
||||
public abstract class Message extends SimpleStreamableObject
|
||||
{
|
||||
/** A timestamp indicating when this message was received from the network. */
|
||||
public transient long received;
|
||||
|
||||
/**
|
||||
* Sets the message transport parameters. For messages received over the network, these
|
||||
* describe the mode of transport over which the message was received. When sending messages,
|
||||
* they act as a hint as to the type of transport desired. Calling this method may have no
|
||||
* effect, depending on whether non-default modes of transport are supported for this message
|
||||
* type.
|
||||
*/
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
// no-op by default
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the message transport parameters.
|
||||
*/
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return Transport.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* For messages sent over the network, this notes the actual type of transport used to deliver
|
||||
* the message. This may not be the same as the hinted transport for various reasons (message
|
||||
* too large to send as datagram, no datagram connection established, etc.)
|
||||
*/
|
||||
public void noteActualTransport (Transport transport)
|
||||
{
|
||||
// no-op by default
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.threerings.presents.dobj.DObject;
|
||||
|
||||
/**
|
||||
* Contains a distributed object to which the client has subscribed.
|
||||
*
|
||||
* @param <T> the type of object delivered by the response.
|
||||
*/
|
||||
public class ObjectResponse<T extends DObject>
|
||||
extends DownstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public ObjectResponse ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an object response with the supplied distributed object.
|
||||
*/
|
||||
public ObjectResponse (T dobj)
|
||||
{
|
||||
_dobj = dobj;
|
||||
}
|
||||
|
||||
public T getObject ()
|
||||
{
|
||||
return _dobj;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=ORSP, msgid=" + messageId + ", obj=" + _dobj + "]";
|
||||
}
|
||||
|
||||
/** The object which is associated with this response. */
|
||||
protected T _dobj;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
import com.threerings.io.ObjectOutputStream;
|
||||
|
||||
/**
|
||||
* Let's the server know we're still alive.
|
||||
*/
|
||||
public class PingRequest extends UpstreamMessage
|
||||
{
|
||||
/** The number of milliseconds of idle upstream that are allowed to elapse before the client
|
||||
* sends a ping message to the server to let it know that we're still alive. */
|
||||
public static final long PING_INTERVAL = 60 * 1000L;
|
||||
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public PingRequest ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ping request using the specified transport.
|
||||
*/
|
||||
public PingRequest (Transport transport)
|
||||
{
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a timestamp that was obtained when this packet was encoded by the low-level
|
||||
* networking code.
|
||||
*/
|
||||
public long getPackStamp ()
|
||||
{
|
||||
return _packStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a timestamp that was obtained when this packet was decoded by the low-level
|
||||
* networking code.
|
||||
*/
|
||||
public long getUnpackStamp ()
|
||||
{
|
||||
return _unpackStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes our custom streamable fields.
|
||||
*/
|
||||
public void writeObject (ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
// grab a timestamp noting when we were encoded into a raw buffer for delivery over the
|
||||
// network
|
||||
_packStamp = System.currentTimeMillis();
|
||||
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads our custom streamable fields.
|
||||
*/
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
// grab a timestamp noting when we were decoded from a raw buffer after being received over
|
||||
// the network
|
||||
_unpackStamp = System.currentTimeMillis();
|
||||
|
||||
in.defaultReadObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return _transport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=PING, msgid=" + messageId + ", transport=" + _transport + "]";
|
||||
}
|
||||
|
||||
/** A time stamp obtained when we serialize this object. */
|
||||
protected transient long _packStamp;
|
||||
|
||||
/** A time stamp obtained when we unserialize this object (the intent is to get a timestamp as
|
||||
* close as possible to when the packet was received on the network). */
|
||||
protected transient long _unpackStamp;
|
||||
|
||||
/** The transport parameters. */
|
||||
protected transient Transport _transport = Transport.DEFAULT;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
import com.threerings.io.ObjectOutputStream;
|
||||
|
||||
import static com.threerings.presents.Log.log;
|
||||
|
||||
/**
|
||||
* Let's the client know the server heard its ping (and that the server and connection are still
|
||||
* alive).
|
||||
*/
|
||||
public class PongResponse extends DownstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public PongResponse ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a pong response which will use the supplied ping time to establish the end-to-end
|
||||
* processing delay introduced by the server.
|
||||
*/
|
||||
public PongResponse (long pingStamp, Transport transport)
|
||||
{
|
||||
// save this for when we are serialized in preparation for delivery over the network
|
||||
_pingStamp = pingStamp;
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which this packet was packed for delivery in the time frame of the
|
||||
* server that sent the packet.
|
||||
*/
|
||||
public long getPackStamp ()
|
||||
{
|
||||
return _packStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of milliseconds that elapsed between the time that the ping which
|
||||
* instigated this pong was read from the network and the time that this pong was written to
|
||||
* the network.
|
||||
*/
|
||||
public int getProcessDelay ()
|
||||
{
|
||||
return _processDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a timestamp that was obtained when this packet was decoded by the low-level
|
||||
* networking code.
|
||||
*/
|
||||
public long getUnpackStamp ()
|
||||
{
|
||||
return _unpackStamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes our custom streamable fields.
|
||||
*/
|
||||
public void writeObject (ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
// make a note of the time at which we were packed
|
||||
_packStamp = System.currentTimeMillis();
|
||||
|
||||
// the time spent between unpacking the ping and packing the pong is the processing delay
|
||||
if (_pingStamp == 0L) {
|
||||
log.warning("Pong response written that was not constructed with a valid ping stamp",
|
||||
"rsp", this);
|
||||
_processDelay = 0;
|
||||
} else {
|
||||
_processDelay = (int)(_packStamp - _pingStamp);
|
||||
}
|
||||
|
||||
out.defaultWriteObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads our custom streamable fields.
|
||||
*/
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
// grab a timestamp noting when we were decoded from a raw buffer after being received over
|
||||
// the network
|
||||
_unpackStamp = System.currentTimeMillis();
|
||||
|
||||
in.defaultReadObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTransport (Transport transport)
|
||||
{
|
||||
_transport = transport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Transport getTransport ()
|
||||
{
|
||||
return _transport;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=PONG, msgid=" + messageId + ", transport=" + _transport + "]";
|
||||
}
|
||||
|
||||
/** The ping unpack stamp provided at construct time to this pong response; only valid on the
|
||||
* sending process, not the receiving process. */
|
||||
protected transient long _pingStamp;
|
||||
|
||||
/** The timestamp obtained immediately before this packet was sent out over the network. */
|
||||
protected long _packStamp;
|
||||
|
||||
/** The delay in milliseconds between the time that the ping request was read from the network
|
||||
* and the time the pong response was written to the network. */
|
||||
protected int _processDelay;
|
||||
|
||||
/** A time stamp obtained when we unserialize this object (the intent is to get a timestamp as
|
||||
* close as possible to when the packet was received on the network). */
|
||||
protected transient long _unpackStamp;
|
||||
|
||||
/** The transport parameters. */
|
||||
protected transient Transport _transport = Transport.DEFAULT;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Credentials used by service clients (peers, bureaus, etc.). A service would extend this class
|
||||
* (so that their service clients can be identified by class name).
|
||||
*/
|
||||
public abstract class ServiceCreds extends Credentials
|
||||
{
|
||||
/** The id of the service client that is authenticating. */
|
||||
public String clientId;
|
||||
|
||||
/**
|
||||
* Creates credentials for the specified client.
|
||||
*/
|
||||
public ServiceCreds (String clientId, String sharedSecret)
|
||||
{
|
||||
this.clientId = clientId;
|
||||
_authToken = createAuthToken(clientId, sharedSecret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used when unserializing an instance from the network.
|
||||
*/
|
||||
public ServiceCreds ()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that these credentials were created with the supplied shared secret.
|
||||
*/
|
||||
public boolean areValid (String sharedSecret)
|
||||
{
|
||||
return createAuthToken(clientId, sharedSecret).equals(_authToken);
|
||||
}
|
||||
|
||||
@Override // from Object
|
||||
public String toString ()
|
||||
{
|
||||
return getClass().getSimpleName() + "[id=" + clientId + ", token=" + _authToken + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a unique password for the specified node using the supplied shared secret.
|
||||
*/
|
||||
protected static String createAuthToken (String clientId, String sharedSecret)
|
||||
{
|
||||
return StringUtil.md5hex(clientId + sharedSecret);
|
||||
}
|
||||
|
||||
/** A token created by a call to {@link #createAuthToken}. */
|
||||
protected String _authToken;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* Requests to subscribe to a particular distributed object.
|
||||
*/
|
||||
public class SubscribeRequest extends UpstreamMessage
|
||||
{
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public SubscribeRequest ()
|
||||
{
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a subscribe request for the distributed object with the
|
||||
* specified object id.
|
||||
*/
|
||||
public SubscribeRequest (int oid)
|
||||
{
|
||||
_oid = oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the oid of the object to which we desire subscription.
|
||||
*/
|
||||
public int getOid ()
|
||||
{
|
||||
return _oid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=SUB, msgid=" + messageId + ", oid=" + _oid + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* The object id of the distributed object to which we are
|
||||
* subscribing.
|
||||
*/
|
||||
protected int _oid;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* Notifies the server that the client has received its {@link UpdateThrottleMessage}.
|
||||
*/
|
||||
public class ThrottleUpdatedMessage extends UpstreamMessage
|
||||
{
|
||||
/** The number of messages allowed per second. */
|
||||
public final int messagesPerSec;
|
||||
|
||||
/**
|
||||
* Zero argument constructor used when unserializing an instance.
|
||||
*/
|
||||
public ThrottleUpdatedMessage ()
|
||||
{
|
||||
this.messagesPerSec = 0;
|
||||
}
|
||||
|
||||
public ThrottleUpdatedMessage (int messagesPerSec)
|
||||
{
|
||||
this.messagesPerSec = messagesPerSec;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
/**
|
||||
* Notifies the server that we would like it to send us datagrams.
|
||||
*/
|
||||
public class TransmitDatagramsRequest extends UpstreamMessage
|
||||
{
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=TRANSMIT_DATAGRAMS, msgid=" + messageId + "]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
//
|
||||
// $Id$
|
||||
//
|
||||
// Narya library - tools for developing networked games
|
||||
// Copyright (C) 2002-2010 Three Rings Design, Inc., All Rights Reserved
|
||||
// http://code.google.com/p/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.net;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
|
||||
/**
|
||||
* Message transport parameters. These include the type of transport and the channel (used to
|
||||
* define independent streams for ordered transport), and may eventually include message priority,
|
||||
* etc.
|
||||
*/
|
||||
public class Transport
|
||||
{
|
||||
/**
|
||||
* The available types of transport.
|
||||
*/
|
||||
public enum Type
|
||||
{
|
||||
/**
|
||||
* Messages are neither guaranteed to arrive nor, if they do arrive, to arrive in order
|
||||
* and without duplicates. Functionally identical to UDP.
|
||||
*/
|
||||
UNRELIABLE_UNORDERED(false, false) {
|
||||
@Override
|
||||
public Type combine (Type other) {
|
||||
return other; // we defer to all
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Messages are not guaranteed to arrive, but if they do arrive, then they will arrive in
|
||||
* order and without duplicates. In other words, out-of-order packets will be dropped.
|
||||
*/
|
||||
UNRELIABLE_ORDERED(false, true) {
|
||||
@Override
|
||||
public Type combine (Type other) {
|
||||
return other.isReliable() ? RELIABLE_ORDERED : this;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Messages are guaranteed to arrive eventually, but they are not guaranteed to arrive in
|
||||
* order.
|
||||
*/
|
||||
RELIABLE_UNORDERED(true, false) {
|
||||
@Override
|
||||
public Type combine (Type other) {
|
||||
return other.isOrdered() ? RELIABLE_ORDERED : this;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Messages are guaranteed to arrive, and will arrive in the order in which they are sent.
|
||||
* Functionally identical to TCP.
|
||||
*/
|
||||
RELIABLE_ORDERED(true, true) {
|
||||
@Override
|
||||
public Type combine (Type other) {
|
||||
return this; // we override all
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether this transport type guarantees that messages will be delivered.
|
||||
*/
|
||||
public boolean isReliable ()
|
||||
{
|
||||
return _reliable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this transport type guarantees that messages will be received in the
|
||||
* order in which they were sent, if they are received at all.
|
||||
*/
|
||||
public boolean isOrdered ()
|
||||
{
|
||||
return _ordered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a transport type that combines the requirements of this type with those of the
|
||||
* specified other type.
|
||||
*/
|
||||
public abstract Type combine (Type other);
|
||||
|
||||
Type (boolean reliable, boolean ordered)
|
||||
{
|
||||
_reliable = reliable;
|
||||
_ordered = ordered;
|
||||
}
|
||||
|
||||
protected boolean _reliable, _ordered;
|
||||
}
|
||||
|
||||
/** The unreliable/unordered mode of transport. */
|
||||
public static final Transport UNRELIABLE_UNORDERED = getInstance(Type.UNRELIABLE_UNORDERED);
|
||||
|
||||
/** The unreliable/ordered mode on the default channel. */
|
||||
public static final Transport UNRELIABLE_ORDERED = getInstance(Type.UNRELIABLE_ORDERED, 0);
|
||||
|
||||
/** The reliable/unordered mode. */
|
||||
public static final Transport RELIABLE_UNORDERED = getInstance(Type.RELIABLE_UNORDERED);
|
||||
|
||||
/** The reliable/ordered mode on the default channel. */
|
||||
public static final Transport RELIABLE_ORDERED = getInstance(Type.RELIABLE_ORDERED, 0);
|
||||
|
||||
/** The default mode of transport. */
|
||||
public static final Transport DEFAULT = RELIABLE_ORDERED;
|
||||
|
||||
/**
|
||||
* Returns the shared instance with the specified parameters.
|
||||
*/
|
||||
public static Transport getInstance (Type type)
|
||||
{
|
||||
return getInstance(type, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared instance with the specified parameters.
|
||||
*/
|
||||
public static Transport getInstance (Type type, int channel)
|
||||
{
|
||||
// were there more parameters in transport objects, it would be better to have a single map
|
||||
// of instances and use Transport objects as keys (as in examples of the flyweight
|
||||
// pattern). however, doing it this way avoids the need to create a new object on lookup
|
||||
if (_unordered == null) {
|
||||
int length = Type.values().length;
|
||||
_unordered = new Transport[length];
|
||||
@SuppressWarnings("unchecked") HashIntMap<Transport>[] ordered = new HashIntMap[length];
|
||||
_ordered = ordered;
|
||||
}
|
||||
|
||||
// for unordered transport, we map on the type alone
|
||||
int idx = type.ordinal();
|
||||
if (!type.isOrdered()) {
|
||||
Transport instance = _unordered[idx];
|
||||
if (instance == null) {
|
||||
_unordered[idx] = instance = new Transport(type);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
// for ordered transport, we map on the type and channel
|
||||
HashIntMap<Transport> instances = _ordered[idx];
|
||||
if (instances == null) {
|
||||
_ordered[idx] = instances = new HashIntMap<Transport>();
|
||||
}
|
||||
Transport instance = instances.get(channel);
|
||||
if (instance == null) {
|
||||
instances.put(channel, instance = new Transport(type, channel));
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of transport.
|
||||
*/
|
||||
public Type getType ()
|
||||
{
|
||||
return _type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the transport channel.
|
||||
*/
|
||||
public int getChannel ()
|
||||
{
|
||||
return _channel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this transport guarantees that messages will be delivered.
|
||||
*/
|
||||
public boolean isReliable ()
|
||||
{
|
||||
return _type.isReliable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this transport guarantees that messages will be received in the order in
|
||||
* which they were sent, if they are received at all.
|
||||
*/
|
||||
public boolean isOrdered ()
|
||||
{
|
||||
return _type.isOrdered();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a transport that satisfies the requirements of this and the specified other
|
||||
* transport.
|
||||
*/
|
||||
public Transport combine (Transport other)
|
||||
{
|
||||
// if the channels are different, we fall back to the default channel
|
||||
return getInstance(
|
||||
_type.combine(other._type),
|
||||
(_channel == other._channel) ? _channel : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode ()
|
||||
{
|
||||
return 31*_type.hashCode() + _channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
Transport otrans;
|
||||
return other instanceof Transport && (otrans = (Transport)other)._type == _type &&
|
||||
otrans._channel == _channel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=" + _type + ", channel=" + _channel + "]";
|
||||
}
|
||||
|
||||
protected Transport (Type type)
|
||||
{
|
||||
this(type, 0);
|
||||
}
|
||||
|
||||
protected Transport (Type type, int channel)
|
||||
{
|
||||
_type = type;
|
||||
_channel = channel;
|
||||
}
|
||||
|
||||
/** The type of transport. */
|
||||
protected Type _type;
|
||||
|
||||
/** The transport channel. */
|
||||
protected int _channel;
|
||||
|
||||
/** Unordered instances mapped by type (would use {@link java.util.EnumMap}, but it doesn't
|
||||
* work with Retroweaver). */
|
||||
protected static Transport[] _unordered;
|
||||
|
||||
/** Ordered instances mapped by type and channel. */
|
||||
protected static HashIntMap<Transport>[] _ordered;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user