Still a work in progress. The new API and base implementations
of the new interfaces. Still exists entirely in parallel with the old code. git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7010 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
This commit is contained in:
parent
f18fb0b287
commit
c551a29022
111
engine/src/networking/com/jme3/network/Client.java
Normal file
111
engine/src/networking/com/jme3/network/Client.java
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a remote connection to a server that can be used
|
||||
* for sending and receiving messages.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface Client extends MessageConnection
|
||||
{
|
||||
/**
|
||||
* Starts the client allowing it to begin processing incoming
|
||||
* messages and delivering them to listeners.
|
||||
*/
|
||||
public void start();
|
||||
|
||||
/**
|
||||
* Returns true if this client is fully connected to the
|
||||
* host.
|
||||
*/
|
||||
public boolean isConnected();
|
||||
|
||||
/**
|
||||
* Returns a unique ID for this client within the remote
|
||||
* server or -1 if this client isn't fully connected to the
|
||||
* server.
|
||||
*/
|
||||
public long getId();
|
||||
|
||||
/**
|
||||
* Sends a message to the server.
|
||||
*/
|
||||
public void send( Message message );
|
||||
|
||||
/**
|
||||
* Closes this connection to the server.
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified about connection
|
||||
* state changes.
|
||||
*/
|
||||
public void addClientStateListener( ClientStateListener listener );
|
||||
|
||||
/**
|
||||
* Removes a previously registered connection listener.
|
||||
*/
|
||||
public void removeClientStateListener( ClientStateListener listener );
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when any message or object
|
||||
* is received from the server.
|
||||
*/
|
||||
public void addMessageListener( MessageListener<? super Client> listener );
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when messages of the specified
|
||||
* types are received.
|
||||
*/
|
||||
public void addMessageListener( MessageListener<? super Client> listener, Class... classes );
|
||||
|
||||
/**
|
||||
* Removes a previously registered wildcard listener. This does
|
||||
* not remove this listener from any type-specific registrations.
|
||||
*/
|
||||
public void removeMessageListener( MessageListener<? super Client> listener );
|
||||
|
||||
/**
|
||||
* Removes a previously registered type-specific listener from
|
||||
* the specified types.
|
||||
*/
|
||||
public void removeMessageListener( MessageListener<? super Client> listener, Class... classes );
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* Listener that is notified about the connection state of
|
||||
* a Client.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface ClientStateListener
|
||||
{
|
||||
/**
|
||||
* Called when the specified client is fully connected to
|
||||
* the remote server.
|
||||
*/
|
||||
public void clientConnected( Client c );
|
||||
|
||||
/**
|
||||
* Called when the client has disconnected from the remote
|
||||
* server.
|
||||
*/
|
||||
public void clientDisconnected( Client c );
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* Listener that is notified about connection arrivals and
|
||||
* removals within a server.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface ConnectionListener
|
||||
{
|
||||
/**
|
||||
* Called when a connection has been added to the specified server and
|
||||
* is fully setup.
|
||||
*/
|
||||
public void connectionAdded( Server server, HostedConnection conn );
|
||||
|
||||
/**
|
||||
* Called when a connection has been removed from the specified
|
||||
* server.
|
||||
*/
|
||||
public void connectionRemoved( Server server, HostedConnection conn );
|
||||
}
|
55
engine/src/networking/com/jme3/network/HostedConnection.java
Normal file
55
engine/src/networking/com/jme3/network/HostedConnection.java
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* This is the connection back to a client that is being
|
||||
* hosted in a server instance.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface HostedConnection extends MessageConnection
|
||||
{
|
||||
/**
|
||||
* Returns the server-unique ID for this client.
|
||||
*/
|
||||
public long getId();
|
||||
|
||||
/**
|
||||
* Closes and removes this connection from the server
|
||||
* sending the optional reason to the remote client.
|
||||
*/
|
||||
public void close( String reason );
|
||||
}
|
47
engine/src/networking/com/jme3/network/Message.java
Normal file
47
engine/src/networking/com/jme3/network/Message.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
import com.jme3.network.serializing.Serializable;
|
||||
|
||||
/**
|
||||
* Interface implemented by all network messages.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
@Serializable()
|
||||
public interface Message
|
||||
{
|
||||
public boolean isReliable();
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* The source of a received message and the common abstract interface
|
||||
* of client->server and server->client objects.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface MessageConnection
|
||||
{
|
||||
/**
|
||||
* Sends a message to the other end of the connection.
|
||||
*/
|
||||
public void send( Message message );
|
||||
}
|
||||
|
45
engine/src/networking/com/jme3/network/MessageListener.java
Normal file
45
engine/src/networking/com/jme3/network/MessageListener.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
|
||||
/**
|
||||
* Listener notified about new messages
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface MessageListener<S>
|
||||
{
|
||||
public void messageReceived( S source, Message m );
|
||||
}
|
92
engine/src/networking/com/jme3/network/Network.java
Normal file
92
engine/src/networking/com/jme3/network/Network.java
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import com.jme3.network.base.DefaultClient;
|
||||
import com.jme3.network.base.DefaultServer;
|
||||
import com.jme3.network.kernel.tcp.SelectorKernel;
|
||||
import com.jme3.network.kernel.tcp.SocketConnector;
|
||||
import com.jme3.network.kernel.udp.UdpConnector;
|
||||
import com.jme3.network.kernel.udp.UdpKernel;
|
||||
|
||||
/**
|
||||
* The main service provider for conveniently creating
|
||||
* server and client instances.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class Network
|
||||
{
|
||||
/**
|
||||
* Creates a Server that will utilize both reliable and fast
|
||||
* transports to communicate with clients. The specified port
|
||||
* will be used for both TCP and UDP communication.
|
||||
*/
|
||||
public static Server createServer( int port ) throws IOException
|
||||
{
|
||||
InetAddress local = InetAddress.getLocalHost();
|
||||
|
||||
UdpKernel fast = new UdpKernel(local, port);
|
||||
SelectorKernel reliable = new SelectorKernel(local,port);
|
||||
|
||||
return new DefaultServer( reliable, fast );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Client that communicates with the specified host and port
|
||||
* using both reliable and fast transports. The localUdpPort specifies the
|
||||
* local port to use for listening for incoming 'fast' UDP messages.
|
||||
*/
|
||||
public static Client connectToServer( String host, int hostPort, int localUdpPort ) throws IOException
|
||||
{
|
||||
return connectToServer( InetAddress.getByName(host), hostPort, localUdpPort );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Client that communicates with the specified address and port
|
||||
* using both reliable and fast transports. The localUdpPort specifies the
|
||||
* local port to use for listening for incoming 'fast' messages.
|
||||
*/
|
||||
public static Client connectToServer( InetAddress address, int port, int localUdpPort ) throws IOException
|
||||
{
|
||||
InetAddress local = InetAddress.getLocalHost();
|
||||
UdpConnector fast = new UdpConnector( local, localUdpPort, address, port );
|
||||
SocketConnector reliable = new SocketConnector( address, port );
|
||||
|
||||
return new DefaultClient( reliable, fast );
|
||||
}
|
||||
}
|
121
engine/src/networking/com/jme3/network/Server.java
Normal file
121
engine/src/networking/com/jme3/network/Server.java
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* Represents a host that can send and receive messages to
|
||||
* a set of remote client connections.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public interface Server
|
||||
{
|
||||
/**
|
||||
* Sends the specified message to all connected clients.
|
||||
*/
|
||||
public void broadcast( Message message );
|
||||
|
||||
/**
|
||||
* Sends the specified message to all connected clients that match
|
||||
* the filter.
|
||||
*/
|
||||
public void broadcast( Object filter, Message message );
|
||||
|
||||
/**
|
||||
* Start the server so that it will began accepting new connections
|
||||
* and processing messages.
|
||||
*/
|
||||
public void start();
|
||||
|
||||
/**
|
||||
* Returns true if the server has been started.
|
||||
*/
|
||||
public boolean isRunning();
|
||||
|
||||
/**
|
||||
* Closes all client connections, stops and running processing threads, and
|
||||
* closes the host connection.
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Retrieves a hosted connection by ID.
|
||||
*/
|
||||
public HostedConnection getConnection( long id );
|
||||
|
||||
/**
|
||||
* Retrieves a read-only collection of all currently connected connections.
|
||||
*/
|
||||
public Collection<HostedConnection> getConnections();
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when new hosted connections
|
||||
* arrive.
|
||||
*/
|
||||
public void addConnectionListener( ConnectionListener listener );
|
||||
|
||||
/**
|
||||
* Removes a previously registered connection listener.
|
||||
*/
|
||||
public void removeConnectionListener( ConnectionListener listener );
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when any message or object
|
||||
* is received from one of the clients.
|
||||
*/
|
||||
public void addMessageListener( MessageListener<? super HostedConnection> listener );
|
||||
|
||||
/**
|
||||
* Adds a listener that will be notified when messages of the specified
|
||||
* types are received from one of the clients.
|
||||
*/
|
||||
public void addMessageListener( MessageListener<? super HostedConnection> listener, Class... classes );
|
||||
|
||||
/**
|
||||
* Removes a previously registered wildcard listener. This does
|
||||
* not remove this listener from any type-specific registrations.
|
||||
*/
|
||||
public void removeMessageListener( MessageListener<? super HostedConnection> listener );
|
||||
|
||||
/**
|
||||
* Removes a previously registered type-specific listener from
|
||||
* the specified types.
|
||||
*/
|
||||
public void removeMessageListener( MessageListener<? super HostedConnection> listener, Class... classes );
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,142 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network.base;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.jme3.network.Message;
|
||||
import com.jme3.network.MessageListener;
|
||||
import com.jme3.network.kernel.Connector;
|
||||
import com.jme3.network.serializing.Serializer;
|
||||
|
||||
/**
|
||||
* Wraps a single Connector and forwards new messages
|
||||
* to the supplied message dispatcher. This is used
|
||||
* by DefaultClient to manage its connector objects.
|
||||
* This is only responsible for message reading and provides
|
||||
* no support for buffering writes.
|
||||
*
|
||||
* <p>This adapter assumes a simple protocol where two
|
||||
* bytes define a (short) object size with the object data
|
||||
* to follow. Note: this limits the size of serialized
|
||||
* objects to 32676 bytes... even though, for example,
|
||||
* datagram packets can hold twice that. :P</p>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class ConnectorAdapter extends Thread
|
||||
{
|
||||
private Connector connector;
|
||||
private MessageListener dispatcher;
|
||||
private AtomicBoolean go = new AtomicBoolean(true);
|
||||
|
||||
public ConnectorAdapter( Connector connector, MessageListener dispatcher )
|
||||
{
|
||||
super( String.valueOf(connector) );
|
||||
this.connector = connector;
|
||||
this.dispatcher = dispatcher;
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
go.set(false);
|
||||
|
||||
// Kill the connector
|
||||
connector.close();
|
||||
}
|
||||
|
||||
protected void createAndDispatch( ByteBuffer buffer )
|
||||
{
|
||||
try {
|
||||
Object obj = Serializer.readClassAndObject( buffer );
|
||||
Message m = (Message)obj;
|
||||
dispatcher.messageReceived( null, m );
|
||||
} catch( IOException e ) {
|
||||
throw new RuntimeException( "Error deserializing object", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
ByteBuffer current = null;
|
||||
int size = 0;
|
||||
|
||||
while( go.get() ) {
|
||||
ByteBuffer buffer = connector.read();
|
||||
|
||||
// push the data from the buffer into as
|
||||
// many messages as we can
|
||||
while( buffer.remaining() > 0 ) {
|
||||
|
||||
if( current == null ) {
|
||||
// We are not currently reading an object so
|
||||
// grab the size.
|
||||
// Note: this is somewhat limiting... int would
|
||||
// be better.
|
||||
size = buffer.getShort();
|
||||
current = ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
if( current.remaining() <= buffer.remaining() ) {
|
||||
// We have at least one complete object so
|
||||
// copy what we can into current, create a message,
|
||||
// and then continue pulling from buffer.
|
||||
|
||||
// Artificially set the limit so we don't overflow
|
||||
int extra = buffer.remaining() - current.remaining();
|
||||
buffer.limit( buffer.position() + current.remaining() );
|
||||
|
||||
// Now copy the data
|
||||
current.put( buffer );
|
||||
current.flip();
|
||||
|
||||
// Now set the limit back to a good value
|
||||
buffer.limit( buffer.position() + extra );
|
||||
|
||||
createAndDispatch( current );
|
||||
|
||||
current = null;
|
||||
} else {
|
||||
|
||||
// Not yet a complete object so just copy what we have
|
||||
current.put( buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
258
engine/src/networking/com/jme3/network/base/DefaultClient.java
Normal file
258
engine/src/networking/com/jme3/network/base/DefaultClient.java
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network.base;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.jme3.network.*;
|
||||
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||
import com.jme3.network.kernel.Connector;
|
||||
import com.jme3.network.serializing.Serializer;
|
||||
|
||||
/**
|
||||
* A default implementation of the Client interface that delegates
|
||||
* its network connectivity to a kernel.Connector.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class DefaultClient implements Client
|
||||
{
|
||||
static Logger log = Logger.getLogger(DefaultClient.class.getName());
|
||||
|
||||
private long id = -1;
|
||||
private boolean isRunning = false;
|
||||
private Connector reliable;
|
||||
private Connector fast;
|
||||
private MessageListenerRegistry<Client> messageListeners = new MessageListenerRegistry<Client>();
|
||||
private List<ClientStateListener> stateListeners = new CopyOnWriteArrayList<ClientStateListener>();
|
||||
private Redispatch dispatcher = new Redispatch();
|
||||
private ConnectorAdapter reliableAdapter;
|
||||
private ConnectorAdapter fastAdapter;
|
||||
|
||||
public DefaultClient( Connector reliable, Connector fast )
|
||||
{
|
||||
this.reliable = reliable;
|
||||
this.fast = fast;
|
||||
if( reliable != null ) {
|
||||
reliableAdapter = new ConnectorAdapter(reliable, dispatcher);
|
||||
}
|
||||
if( fast != null ) {
|
||||
fastAdapter = new ConnectorAdapter(fast, dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
protected void checkRunning()
|
||||
{
|
||||
if( !isRunning )
|
||||
throw new IllegalStateException( "Client is not started." );
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
if( isRunning )
|
||||
throw new IllegalStateException( "Client is already started." );
|
||||
|
||||
// Start up the threads and stuff
|
||||
if( reliableAdapter != null ) {
|
||||
reliableAdapter.start();
|
||||
}
|
||||
if( fastAdapter != null ) {
|
||||
fastAdapter.start();
|
||||
}
|
||||
|
||||
// Send our connection message with a generated ID until
|
||||
// we get one back from the server. We'll hash time in
|
||||
// millis and time in nanos.
|
||||
long tempId = System.currentTimeMillis() ^ System.nanoTime();
|
||||
|
||||
// Set it true here so we can send some messages.
|
||||
isRunning = true;
|
||||
|
||||
ClientRegistrationMessage reg;
|
||||
if( reliable != null ) {
|
||||
reg = new ClientRegistrationMessage();
|
||||
reg.setId(tempId);
|
||||
reg.setReliable(true);
|
||||
send(reg);
|
||||
}
|
||||
if( fast != null ) {
|
||||
// We create two different ones to prepare for someday
|
||||
// when there will probably be threaded sending.
|
||||
reg = new ClientRegistrationMessage();
|
||||
reg.setId(tempId);
|
||||
reg.setReliable(false);
|
||||
send(reg);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isConnected()
|
||||
{
|
||||
return id != -1; // for now
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
protected ByteBuffer messageToBuffer( Message message )
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocate( 32767 + 2 );
|
||||
|
||||
try {
|
||||
buffer.position( 2 );
|
||||
Serializer.writeClassAndObject( buffer, message );
|
||||
buffer.flip();
|
||||
short dataLength = (short)(buffer.remaining() - 2);
|
||||
buffer.putShort( dataLength );
|
||||
buffer.position( 0 );
|
||||
|
||||
return buffer;
|
||||
} catch( IOException e ) {
|
||||
throw new RuntimeException( "Error serializing message", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void send( Message message )
|
||||
{
|
||||
checkRunning();
|
||||
|
||||
// For now just send direclty. We allocate our
|
||||
// own buffer each time because this method might
|
||||
// be called from multiple threads. If writing
|
||||
// is queued into its own thread then that could
|
||||
// be shared.
|
||||
ByteBuffer buffer = messageToBuffer(message);
|
||||
if( message.isReliable() || fast == null ) {
|
||||
if( reliable == null )
|
||||
throw new RuntimeException( "No reliable connector configured" );
|
||||
reliable.write(buffer);
|
||||
} else {
|
||||
fast.write(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
checkRunning();
|
||||
|
||||
// Send a close message
|
||||
|
||||
// Tell the thread it's ok to die
|
||||
if( fastAdapter != null ) {
|
||||
fastAdapter.close();
|
||||
}
|
||||
if( reliableAdapter != null ) {
|
||||
reliableAdapter.close();
|
||||
}
|
||||
|
||||
// Wait for the threads?
|
||||
|
||||
fireDisconnected();
|
||||
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
public void addClientStateListener( ClientStateListener listener )
|
||||
{
|
||||
stateListeners.add( listener );
|
||||
}
|
||||
|
||||
public void removeClientStateListener( ClientStateListener listener )
|
||||
{
|
||||
stateListeners.remove( listener );
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super Client> listener )
|
||||
{
|
||||
messageListeners.addMessageListener( listener );
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super Client> listener, Class... classes )
|
||||
{
|
||||
messageListeners.addMessageListener( listener, classes );
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super Client> listener )
|
||||
{
|
||||
messageListeners.removeMessageListener( listener );
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super Client> listener, Class... classes )
|
||||
{
|
||||
messageListeners.removeMessageListener( listener, classes );
|
||||
}
|
||||
|
||||
protected void fireConnected()
|
||||
{
|
||||
for( ClientStateListener l : stateListeners ) {
|
||||
l.clientConnected( this );
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireDisconnected()
|
||||
{
|
||||
for( ClientStateListener l : stateListeners ) {
|
||||
l.clientDisconnected( this );
|
||||
}
|
||||
}
|
||||
|
||||
protected void dispatch( Message m )
|
||||
{
|
||||
// Pull off the connection management messages we're
|
||||
// interested in and then pass on the rest.
|
||||
if( m instanceof ClientRegistrationMessage ) {
|
||||
// Then we've gotten our real id
|
||||
this.id = ((ClientRegistrationMessage)m).getId();
|
||||
log.log( Level.INFO, "Connection established, id:{0}.", this.id );
|
||||
fireConnected();
|
||||
return;
|
||||
}
|
||||
|
||||
messageListeners.messageReceived( this, m );
|
||||
}
|
||||
|
||||
protected class Redispatch implements MessageListener
|
||||
{
|
||||
public void messageReceived( Object source, Message m )
|
||||
{
|
||||
dispatch( m );
|
||||
}
|
||||
}
|
||||
}
|
390
engine/src/networking/com/jme3/network/base/DefaultServer.java
Normal file
390
engine/src/networking/com/jme3/network/base/DefaultServer.java
Normal file
@ -0,0 +1,390 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network.base;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import com.jme3.network.*;
|
||||
import com.jme3.network.kernel.*;
|
||||
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||
import com.jme3.network.serializing.Serializer;
|
||||
|
||||
/**
|
||||
* A default implementation of the Server interface that delegates
|
||||
* its network connectivity to kernel.Kernel.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class DefaultServer implements Server
|
||||
{
|
||||
private boolean isRunning = false;
|
||||
private AtomicLong nextId = new AtomicLong(0);
|
||||
private Kernel reliable;
|
||||
private KernelAdapter reliableAdapter;
|
||||
private Kernel fast;
|
||||
private KernelAdapter fastAdapter;
|
||||
private Redispatch dispatcher = new Redispatch();
|
||||
private Map<Long,HostedConnection> connections = new ConcurrentHashMap<Long,HostedConnection>();
|
||||
private Map<Endpoint,HostedConnection> endpointConnections
|
||||
= new ConcurrentHashMap<Endpoint,HostedConnection>();
|
||||
|
||||
// Keeps track of clients for whom we've only received the UDP
|
||||
// registration message
|
||||
private Map<Long,Connection> connecting = new ConcurrentHashMap<Long,Connection>();
|
||||
|
||||
private MessageListenerRegistry<HostedConnection> messageListeners
|
||||
= new MessageListenerRegistry<HostedConnection>();
|
||||
private List<ConnectionListener> connectionListeners = new CopyOnWriteArrayList<ConnectionListener>();
|
||||
|
||||
public DefaultServer( Kernel reliable, Kernel fast )
|
||||
{
|
||||
this.reliable = reliable;
|
||||
this.fast = fast;
|
||||
|
||||
if( reliable != null ) {
|
||||
reliableAdapter = new KernelAdapter( this, reliable, dispatcher );
|
||||
}
|
||||
if( fast != null ) {
|
||||
fastAdapter = new KernelAdapter( this, fast, dispatcher );
|
||||
}
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
if( isRunning )
|
||||
throw new IllegalStateException( "Server is already started." );
|
||||
|
||||
// Initialize the kernels
|
||||
if( reliable != null ) {
|
||||
reliable.initialize();
|
||||
}
|
||||
if( fast != null ) {
|
||||
fast.initialize();
|
||||
}
|
||||
|
||||
// Start em up
|
||||
if( reliableAdapter != null ) {
|
||||
reliableAdapter.start();
|
||||
}
|
||||
if( fastAdapter != null ) {
|
||||
fastAdapter.start();
|
||||
}
|
||||
|
||||
isRunning = true;
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public void close()
|
||||
{
|
||||
if( !isRunning )
|
||||
throw new IllegalStateException( "Server is not started." );
|
||||
|
||||
try {
|
||||
// Kill the adpaters, they will kill the kernels
|
||||
if( fastAdapter != null ) {
|
||||
fastAdapter.close();
|
||||
}
|
||||
if( reliableAdapter != null ) {
|
||||
reliableAdapter.close();
|
||||
|
||||
isRunning = false;
|
||||
}
|
||||
} catch( InterruptedException e ) {
|
||||
throw new RuntimeException( "Interrupted while closing", e );
|
||||
}
|
||||
}
|
||||
|
||||
protected ByteBuffer messageToBuffer( Message message )
|
||||
{
|
||||
ByteBuffer buffer = ByteBuffer.allocate( 32767 + 2 );
|
||||
|
||||
try {
|
||||
buffer.position( 2 );
|
||||
Serializer.writeClassAndObject( buffer, message );
|
||||
buffer.flip();
|
||||
short dataLength = (short)(buffer.remaining() - 2);
|
||||
buffer.putShort( dataLength );
|
||||
buffer.position( 0 );
|
||||
|
||||
return buffer;
|
||||
} catch( IOException e ) {
|
||||
throw new RuntimeException( "Error serializing message", e );
|
||||
}
|
||||
}
|
||||
|
||||
public void broadcast( Message message )
|
||||
{
|
||||
broadcast( null, message );
|
||||
}
|
||||
|
||||
public void broadcast( Object filter, Message message )
|
||||
{
|
||||
ByteBuffer buffer = messageToBuffer(message);
|
||||
|
||||
// Ignore the filter for the moment
|
||||
if( message.isReliable() || fast == null ) {
|
||||
if( reliable == null )
|
||||
throw new RuntimeException( "No reliable kernel configured" );
|
||||
reliable.broadcast( filter, buffer, true );
|
||||
} else {
|
||||
fast.broadcast( filter, buffer, false );
|
||||
}
|
||||
}
|
||||
|
||||
public HostedConnection getConnection( long id )
|
||||
{
|
||||
return connections.get(id);
|
||||
}
|
||||
|
||||
public Collection<HostedConnection> getConnections()
|
||||
{
|
||||
return Collections.unmodifiableCollection((Collection<HostedConnection>)connections.values());
|
||||
}
|
||||
|
||||
public void addConnectionListener( ConnectionListener listener )
|
||||
{
|
||||
connectionListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeConnectionListener( ConnectionListener listener )
|
||||
{
|
||||
connectionListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super HostedConnection> listener )
|
||||
{
|
||||
messageListeners.addMessageListener( listener );
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super HostedConnection> listener, Class... classes )
|
||||
{
|
||||
messageListeners.addMessageListener( listener, classes );
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super HostedConnection> listener )
|
||||
{
|
||||
messageListeners.removeMessageListener( listener );
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super HostedConnection> listener, Class... classes )
|
||||
{
|
||||
messageListeners.removeMessageListener( listener, classes );
|
||||
}
|
||||
|
||||
protected void dispatch( HostedConnection source, Message m )
|
||||
{
|
||||
messageListeners.messageReceived( source, m );
|
||||
}
|
||||
|
||||
protected void fireConnectionAdded( HostedConnection conn )
|
||||
{
|
||||
for( ConnectionListener l : connectionListeners ) {
|
||||
l.connectionAdded( this, conn );
|
||||
}
|
||||
}
|
||||
|
||||
protected void fireConnectionRemoved( HostedConnection conn )
|
||||
{
|
||||
for( ConnectionListener l : connectionListeners ) {
|
||||
l.connectionRemoved( this, conn );
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerClient( KernelAdapter ka, Endpoint p, ClientRegistrationMessage m )
|
||||
{
|
||||
Connection addedConnection = null;
|
||||
|
||||
// generally this will only be called by one thread but it's
|
||||
// important enough I won't take chances
|
||||
synchronized( this ) {
|
||||
// Grab the random ID that the client created when creating
|
||||
// its two registration messages
|
||||
long tempId = m.getId();
|
||||
|
||||
// See if we already have one
|
||||
Connection c = connecting.remove(tempId);
|
||||
if( c == null ) {
|
||||
c = new Connection();
|
||||
}
|
||||
|
||||
// Fill in what we now know
|
||||
if( ka == fastAdapter ) {
|
||||
c.fast = p;
|
||||
|
||||
if( c.reliable == null ) {
|
||||
// Tuck it away for later
|
||||
connecting.put(tempId, c);
|
||||
}
|
||||
|
||||
} else {
|
||||
// It must be the reliable one
|
||||
c.reliable = p;
|
||||
|
||||
if( c.fast == null && fastAdapter != null ) {
|
||||
// Still waiting for the fast connection to
|
||||
// register
|
||||
connecting.put(tempId, c);
|
||||
}
|
||||
}
|
||||
|
||||
if( !connecting.containsKey(tempId) ) {
|
||||
|
||||
// Then we are fully connected
|
||||
if( connections.put( c.getId(), c ) == null ) {
|
||||
|
||||
if( c.fast != null ) {
|
||||
endpointConnections.put( c.fast, c );
|
||||
}
|
||||
endpointConnections.put( c.reliable, c );
|
||||
|
||||
addedConnection = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Best to do this outside of the synch block to avoid
|
||||
// over synchronizing which is the path to deadlocks
|
||||
if( addedConnection != null ) {
|
||||
// Nnow we can notify the listeners about the
|
||||
// new connection.
|
||||
fireConnectionAdded( addedConnection );
|
||||
|
||||
// Send the ID back to the client letting it know it's
|
||||
// fully connected.
|
||||
m = new ClientRegistrationMessage();
|
||||
m.setId( addedConnection.getId() );
|
||||
m.setReliable(true);
|
||||
addedConnection.send(m);
|
||||
}
|
||||
}
|
||||
|
||||
protected HostedConnection getConnection( Endpoint endpoint )
|
||||
{
|
||||
return endpointConnections.get(endpoint);
|
||||
}
|
||||
|
||||
protected void connectionClosed( Endpoint p )
|
||||
{
|
||||
// Try to find the endpoint in all ways that it might
|
||||
// exist. Note: by this point the channel is closed
|
||||
// already.
|
||||
|
||||
// Also note: this method will be called twice per
|
||||
// HostedConnection if it has two endpoints.
|
||||
|
||||
Connection removed = null;
|
||||
synchronized( this ) {
|
||||
// Just in case the endpoint was still connecting
|
||||
connecting.values().remove(p);
|
||||
|
||||
// And the regular management
|
||||
removed = (Connection)endpointConnections.remove(p);
|
||||
if( removed != null ) {
|
||||
connections.remove( removed.getId() );
|
||||
}
|
||||
}
|
||||
|
||||
// Better not to fire events while we hold a lock
|
||||
// so always do this outside the synch block.
|
||||
if( removed != null ) {
|
||||
|
||||
// Make sure both endpoints are closed. Note: reliable
|
||||
// should always already be closed through all paths that I
|
||||
// can conceive... but it doesn't hurt to be sure.
|
||||
if( removed.reliable != null && removed.reliable.isConnected() ) {
|
||||
removed.reliable.close();
|
||||
}
|
||||
if( removed.fast != null && removed.fast.isConnected() ) {
|
||||
removed.fast.close();
|
||||
}
|
||||
|
||||
fireConnectionRemoved( removed );
|
||||
}
|
||||
}
|
||||
|
||||
protected class Connection implements HostedConnection
|
||||
{
|
||||
private long id;
|
||||
private Endpoint reliable;
|
||||
private Endpoint fast;
|
||||
|
||||
public Connection()
|
||||
{
|
||||
id = nextId.getAndIncrement();
|
||||
}
|
||||
|
||||
public long getId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
public void send( Message message )
|
||||
{
|
||||
ByteBuffer buffer = messageToBuffer(message);
|
||||
if( message.isReliable() || fast == null ) {
|
||||
reliable.send( buffer );
|
||||
} else {
|
||||
fast.send( buffer );
|
||||
}
|
||||
}
|
||||
|
||||
public void close( String reason )
|
||||
{
|
||||
// Send a reason
|
||||
|
||||
// Just close the reliable endpoint
|
||||
// fast will be cleaned up as a side-effect
|
||||
if( reliable != null ) {
|
||||
reliable.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class Redispatch implements MessageListener<HostedConnection>
|
||||
{
|
||||
public void messageReceived( HostedConnection source, Message m )
|
||||
{
|
||||
dispatch( source, m );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
210
engine/src/networking/com/jme3/network/base/KernelAdapter.java
Normal file
210
engine/src/networking/com/jme3/network/base/KernelAdapter.java
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network.base;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.jme3.network.*;
|
||||
import com.jme3.network.kernel.Endpoint;
|
||||
import com.jme3.network.kernel.EndpointEvent;
|
||||
import com.jme3.network.kernel.Envelope;
|
||||
import com.jme3.network.kernel.Kernel;
|
||||
import com.jme3.network.message.ClientRegistrationMessage; //hopefully temporary
|
||||
import com.jme3.network.serializing.Serializer;
|
||||
|
||||
/**
|
||||
* Wraps a single Kernel and forwards new messages
|
||||
* to the supplied message dispatcher and new endpoint
|
||||
* events to the connection dispatcher. This is used
|
||||
* by DefaultServer to manage its kernel objects.
|
||||
*
|
||||
* <p>This adapter assumes a simple protocol where two
|
||||
* bytes define a (short) object size with the object data
|
||||
* to follow. Note: this limits the size of serialized
|
||||
* objects to 32676 bytes... even though, for example,
|
||||
* datagram packets can hold twice that. :P</p>
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class KernelAdapter extends Thread
|
||||
{
|
||||
private DefaultServer server; // this is unfortunate
|
||||
private Kernel kernel;
|
||||
private MessageListener messageDispatcher;
|
||||
private AtomicBoolean go = new AtomicBoolean(true);
|
||||
|
||||
public KernelAdapter( DefaultServer server, Kernel kernel, MessageListener messageDispatcher )
|
||||
{
|
||||
super( String.valueOf(kernel) );
|
||||
this.server = server;
|
||||
this.kernel = kernel;
|
||||
this.messageDispatcher = messageDispatcher;
|
||||
setDaemon(true);
|
||||
}
|
||||
|
||||
public void close() throws InterruptedException
|
||||
{
|
||||
go.set(false);
|
||||
|
||||
// Kill the kernel
|
||||
kernel.terminate();
|
||||
}
|
||||
|
||||
protected HostedConnection getConnection( Endpoint p )
|
||||
{
|
||||
return server.getConnection(p);
|
||||
}
|
||||
|
||||
protected void connectionClosed( Endpoint p )
|
||||
{
|
||||
server.connectionClosed(p);
|
||||
}
|
||||
|
||||
protected void createAndDispatch( Endpoint p, ByteBuffer buffer )
|
||||
{
|
||||
try {
|
||||
Object obj = Serializer.readClassAndObject( buffer );
|
||||
Message m = (Message)obj;
|
||||
|
||||
// Because this class is the only one with the information
|
||||
// to do it... we need to pull of the registration message
|
||||
// here.
|
||||
if( m instanceof ClientRegistrationMessage ) {
|
||||
server.registerClient( this, p, (ClientRegistrationMessage)m );
|
||||
return;
|
||||
}
|
||||
|
||||
HostedConnection source = getConnection(p);
|
||||
messageDispatcher.messageReceived( source, m );
|
||||
} catch( IOException e ) {
|
||||
throw new RuntimeException( "Error deserializing object", e );
|
||||
}
|
||||
}
|
||||
|
||||
protected void createAndDispatch( Envelope env )
|
||||
{
|
||||
byte[] data = env.getData();
|
||||
ByteBuffer buffer = ByteBuffer.wrap(data);
|
||||
|
||||
ByteBuffer current = null;
|
||||
int size = 0;
|
||||
|
||||
// push the data from the buffer into as
|
||||
// many messages as we can
|
||||
while( buffer.remaining() > 0 ) {
|
||||
|
||||
if( current == null ) {
|
||||
// We are not currently reading an object so
|
||||
// grab the size.
|
||||
// Note: this is somewhat limiting... int would
|
||||
// be better.
|
||||
size = buffer.getShort();
|
||||
current = ByteBuffer.allocate(size);
|
||||
}
|
||||
|
||||
if( current.remaining() <= buffer.remaining() ) {
|
||||
// We have at least one complete object so
|
||||
// copy what we can into current, create a message,
|
||||
// and then continue pulling from buffer.
|
||||
|
||||
// Artificially set the limit so we don't overflow
|
||||
int extra = buffer.remaining() - current.remaining();
|
||||
buffer.limit( buffer.position() + current.remaining() );
|
||||
|
||||
// Now copy the data
|
||||
current.put( buffer );
|
||||
current.flip();
|
||||
|
||||
// Now set the limit back to a good value
|
||||
buffer.limit( buffer.position() + extra );
|
||||
|
||||
createAndDispatch( env.getSource(), current );
|
||||
|
||||
current = null;
|
||||
} else {
|
||||
|
||||
// Not yet a complete object so just copy what we have
|
||||
current.put( buffer );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected void createAndDispatch( EndpointEvent event )
|
||||
{
|
||||
// Only need to tell the server about disconnects
|
||||
if( event.getType() == EndpointEvent.Type.REMOVE ) {
|
||||
connectionClosed( event.getEndpoint() );
|
||||
}
|
||||
}
|
||||
|
||||
protected void flushEvents()
|
||||
{
|
||||
EndpointEvent event;
|
||||
while( (event = kernel.nextEvent()) != null )
|
||||
{
|
||||
createAndDispatch( event );
|
||||
}
|
||||
}
|
||||
|
||||
public void run()
|
||||
{
|
||||
while( go.get() ) {
|
||||
|
||||
try {
|
||||
// Check for pending events
|
||||
flushEvents();
|
||||
|
||||
// Grab the next envelope
|
||||
Envelope e = kernel.read();
|
||||
|
||||
// Check for pending events that might have
|
||||
// come in while we were blocking. This is usually
|
||||
// when the connection add events come through
|
||||
flushEvents();
|
||||
|
||||
createAndDispatch( e );
|
||||
} catch( InterruptedException ex ) {
|
||||
if( !go.get() )
|
||||
return;
|
||||
throw new RuntimeException( "Unexpected interruption", ex );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2011 jMonkeyEngine
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package com.jme3.network.base;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import com.jme3.network.Message;
|
||||
import com.jme3.network.MessageListener;
|
||||
|
||||
/**
|
||||
* Keeps track of message listeners registered to specific
|
||||
* types or to any type.
|
||||
*
|
||||
* @version $Revision$
|
||||
* @author Paul Speed
|
||||
*/
|
||||
public class MessageListenerRegistry<S> implements MessageListener<S>
|
||||
{
|
||||
private List<MessageListener<? super S>> listeners = new CopyOnWriteArrayList<MessageListener<? super S>>();
|
||||
private Map<Class,List<MessageListener<? super S>>> typeListeners
|
||||
= new ConcurrentHashMap<Class,List<MessageListener<? super S>>>();
|
||||
|
||||
public MessageListenerRegistry()
|
||||
{
|
||||
}
|
||||
|
||||
public void messageReceived( S source, Message m )
|
||||
{
|
||||
for( MessageListener<? super S> l : listeners ) {
|
||||
l.messageReceived( source, m );
|
||||
}
|
||||
|
||||
for( MessageListener<? super S> l : getListeners(m.getClass(),false) ) {
|
||||
l.messageReceived( source, m );
|
||||
}
|
||||
}
|
||||
|
||||
protected List<MessageListener<? super S>> getListeners( Class c, boolean create )
|
||||
{
|
||||
List<MessageListener<? super S>> result = typeListeners.get(c);
|
||||
if( result == null && create ) {
|
||||
result = new CopyOnWriteArrayList<MessageListener<? super S>>();
|
||||
typeListeners.put( c, result );
|
||||
}
|
||||
|
||||
if( result == null ) {
|
||||
result = Collections.emptyList();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super S> listener )
|
||||
{
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super S> listener )
|
||||
{
|
||||
listeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addMessageListener( MessageListener<? super S> listener, Class... classes )
|
||||
{
|
||||
for( Class c : classes ) {
|
||||
getListeners(c, true).add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeMessageListener( MessageListener<? super S> listener, Class... classes )
|
||||
{
|
||||
for( Class c : classes ) {
|
||||
getListeners(c, false).remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
@ -44,7 +44,7 @@ import com.jme3.network.serializing.Serializable;
|
||||
* @author Lars Wesselius
|
||||
*/
|
||||
@Serializable()
|
||||
public class Message {
|
||||
public class Message implements com.jme3.network.Message {
|
||||
// The connector this message is meant for.
|
||||
private transient Client connector;
|
||||
private transient Connection connection;
|
||||
|
Loading…
x
Reference in New Issue
Block a user