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-0572b91ccdca3.0
parent
f18fb0b287
commit
c551a29022
@ -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 ); |
||||||
|
} |
@ -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 ); |
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
|
@ -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 ); |
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 ); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue