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
3.0
PSp..om 14 years ago
parent f18fb0b287
commit c551a29022
  1. 111
      engine/src/networking/com/jme3/network/Client.java
  2. 56
      engine/src/networking/com/jme3/network/ClientStateListener.java
  3. 56
      engine/src/networking/com/jme3/network/ConnectionListener.java
  4. 55
      engine/src/networking/com/jme3/network/HostedConnection.java
  5. 47
      engine/src/networking/com/jme3/network/Message.java
  6. 50
      engine/src/networking/com/jme3/network/MessageConnection.java
  7. 45
      engine/src/networking/com/jme3/network/MessageListener.java
  8. 92
      engine/src/networking/com/jme3/network/Network.java
  9. 121
      engine/src/networking/com/jme3/network/Server.java
  10. 142
      engine/src/networking/com/jme3/network/base/ConnectorAdapter.java
  11. 258
      engine/src/networking/com/jme3/network/base/DefaultClient.java
  12. 390
      engine/src/networking/com/jme3/network/base/DefaultServer.java
  13. 210
      engine/src/networking/com/jme3/network/base/KernelAdapter.java
  14. 106
      engine/src/networking/com/jme3/network/base/MessageListenerRegistry.java
  15. 2
      engine/src/networking/com/jme3/network/message/Message.java

@ -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);
}
}
}

@ -44,7 +44,7 @@ import com.jme3.network.serializing.Serializable;
* @author Lars Wesselius * @author Lars Wesselius
*/ */
@Serializable() @Serializable()
public class Message { public class Message implements com.jme3.network.Message {
// The connector this message is meant for. // The connector this message is meant for.
private transient Client connector; private transient Client connector;
private transient Connection connection; private transient Connection connection;

Loading…
Cancel
Save