with custom subclasses and service interfaces for client services and server-side services (HostedServices). This code is a copy and refactoring of code I developed for Mythruna... it worked there but I haven't tested it yet in its new form. Things may change as I integrate this more closely with the core Client and Server classes. I wanted to get it into source control first. Also included an RPC service implementation which can serve as the underpinning for other things. Coming soon: serializer registration service and a simple RMI service based on the RPC layer.experimental
parent
9abedf284e
commit
1eb2ba7276
@ -0,0 +1,51 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convenient base class for ClientServices providing some default ClientService |
||||||
|
* interface implementations as well as a few convenience methods |
||||||
|
* such as getServiceManager() and getService(type). Subclasses |
||||||
|
* must at least override the onInitialize() method to handle |
||||||
|
* service initialization. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public abstract class AbstractClientService extends AbstractService<ClientServiceManager> |
||||||
|
implements ClientService { |
||||||
|
|
||||||
|
protected AbstractClientService() { |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
import com.jme3.network.HostedConnection; |
||||||
|
import com.jme3.network.Server; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Convenient base class for HostedServices providing some default HostedService |
||||||
|
* interface implementations as well as a few convenience methods |
||||||
|
* such as getServiceManager() and getService(type). Subclasses |
||||||
|
* must at least override the onInitialize() method to handle |
||||||
|
* service initialization. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public abstract class AbstractHostedService extends AbstractService<HostedServiceManager> |
||||||
|
implements HostedService { |
||||||
|
|
||||||
|
protected AbstractHostedService() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation does nothing. Implementations can |
||||||
|
* override this to peform custom new connection behavior. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void connectionAdded(Server server, HostedConnection hc) { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation does nothing. Implementations can |
||||||
|
* override this to peform custom leaving connection behavior. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void connectionRemoved(Server server, HostedConnection hc) { |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,111 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Base class providing some default Service interface implementations |
||||||
|
* as well as a few convenience methods such as getServiceManager() |
||||||
|
* and getService(type). Subclasses must at least override the |
||||||
|
* onInitialize() method to handle service initialization. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public abstract class AbstractService<S extends ServiceManager> implements Service<S> { |
||||||
|
|
||||||
|
private S serviceManager; |
||||||
|
|
||||||
|
protected AbstractService() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the ServiceManager that was passed to |
||||||
|
* initialize() during service initialization. |
||||||
|
*/ |
||||||
|
protected S getServiceManager() { |
||||||
|
return serviceManager; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the first sibling service of the specified |
||||||
|
* type. |
||||||
|
*/ |
||||||
|
protected <T extends Service<S>> T getService( Class<T> type ) { |
||||||
|
return type.cast(serviceManager.getService(type)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Initializes this service by keeping a reference to |
||||||
|
* the service manager and calling onInitialize(). |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public final void initialize( S serviceManager ) { |
||||||
|
this.serviceManager = serviceManager; |
||||||
|
onInitialize(serviceManager); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called during initialize() for the subclass to perform |
||||||
|
* implementation specific initialization. |
||||||
|
*/ |
||||||
|
protected abstract void onInitialize( S serviceManager ); |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation does nothing. Implementations can |
||||||
|
* override this to peform custom startup behavior. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void start() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation does nothing. Implementations can |
||||||
|
* override this to peform custom stop behavior. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void stop() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation does nothing. Implementations can |
||||||
|
* override this to peform custom termination behavior. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void terminate( S serviceManager ) { |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getClass().getName() + "[serviceManager=" + serviceManager + "]"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Interface implemented by Client-side services that augment |
||||||
|
* a network Client's functionality. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public interface ClientService extends Service<ClientServiceManager> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is first attached to the service |
||||||
|
* manager. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void initialize( ClientServiceManager serviceManager ); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service manager is started or if the |
||||||
|
* service is added to an already started service manager. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void start(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is shutting down. All services |
||||||
|
* are stopped and any service manager resources are closed |
||||||
|
* before the services are terminated. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void stop(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The service manager is fully shutting down. All services |
||||||
|
* have been stopped and related connections closed. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void terminate( ClientServiceManager serviceManager ); |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
import com.jme3.network.Client; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Manages ClientServices on behalf of a network Client object. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public class ClientServiceManager extends ServiceManager<ClientServiceManager> { |
||||||
|
|
||||||
|
private Client client; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new ClientServiceManager for the specified network Client. |
||||||
|
*/ |
||||||
|
public ClientServiceManager( Client client ) { |
||||||
|
this.client = client; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the network Client associated with this ClientServiceManager. |
||||||
|
*/ |
||||||
|
public Client getClient() { |
||||||
|
return client; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns 'this' and is what is passed to ClientService.initialize() |
||||||
|
* and ClientService.termnate(); |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected final ClientServiceManager getParent() { |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the specified ClientService and initializes it. If the service manager |
||||||
|
* has already been started then the service will also be started. |
||||||
|
*/ |
||||||
|
public void addService( ClientService s ) { |
||||||
|
super.addService(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes the specified ClientService from this service manager, stopping |
||||||
|
* and terminating it as required. If this service manager is in a |
||||||
|
* started state then the service will be stopped. After removal, |
||||||
|
* the service will be terminated. |
||||||
|
*/ |
||||||
|
public void removeService( ClientService s ) { |
||||||
|
super.removeService(s); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,74 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
import com.jme3.network.ConnectionListener; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Interface implemented by Server-side services that augment |
||||||
|
* a network Server's functionality. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public interface HostedService extends Service<HostedServiceManager>, ConnectionListener { |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is first attached to the service |
||||||
|
* manager. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void initialize( HostedServiceManager serviceManager ); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service manager is started or if the |
||||||
|
* service is added to an already started service manager. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void start(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is shutting down. All services |
||||||
|
* are stopped and any service manager resources are closed |
||||||
|
* before the services are terminated. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void stop(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The service manager is fully shutting down. All services |
||||||
|
* have been stopped and related connections closed. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void terminate( HostedServiceManager serviceManager ); |
||||||
|
} |
@ -0,0 +1,127 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
import com.jme3.network.ConnectionListener; |
||||||
|
import com.jme3.network.HostedConnection; |
||||||
|
import com.jme3.network.Server; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Manages HostedServices on behalf of a network Server object. |
||||||
|
* All HostedServices are automatically informed about new and |
||||||
|
* leaving connections. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public class HostedServiceManager extends ServiceManager<HostedServiceManager> { |
||||||
|
|
||||||
|
private Server server; |
||||||
|
private ConnectionObserver connectionObserver; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a HostedServiceManager for the specified network Server. |
||||||
|
*/ |
||||||
|
public HostedServiceManager( Server server ) { |
||||||
|
this.server = server; |
||||||
|
this.connectionObserver = new ConnectionObserver(); |
||||||
|
server.addConnectionListener(connectionObserver); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the network Server associated with this HostedServiceManager. |
||||||
|
*/ |
||||||
|
public Server getServer() { |
||||||
|
return server; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns 'this' and is what is passed to HostedService.initialize() |
||||||
|
* and HostedService.termnate(); |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected final HostedServiceManager getParent() { |
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the specified HostedService and initializes it. If the service manager |
||||||
|
* has already been started then the service will also be started. |
||||||
|
*/ |
||||||
|
public void addService( HostedService s ) { |
||||||
|
super.addService(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes the specified HostedService from this service manager, stopping |
||||||
|
* and terminating it as required. If this service manager is in a |
||||||
|
* started state then the service will be stopped. After removal, |
||||||
|
* the service will be terminated. |
||||||
|
*/ |
||||||
|
public void removeService( HostedService s ) { |
||||||
|
super.removeService(s); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when a new connection has been added so that the |
||||||
|
* services can be notified. |
||||||
|
*/ |
||||||
|
protected void addConnection( HostedConnection hc ) { |
||||||
|
for( Service s : getServices() ) { |
||||||
|
((HostedService)s).connectionAdded(server, hc); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when a connection has been removed so that the |
||||||
|
* services can be notified. |
||||||
|
*/ |
||||||
|
protected void removeConnection( HostedConnection hc ) { |
||||||
|
for( Service s : getServices() ) { |
||||||
|
((HostedService)s).connectionRemoved(server, hc); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected class ConnectionObserver implements ConnectionListener { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void connectionAdded(Server server, HostedConnection hc) { |
||||||
|
addConnection(hc); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void connectionRemoved(Server server, HostedConnection hc) { |
||||||
|
removeConnection(hc); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* The base interface for managed services. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public interface Service<S> { |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is first attached to the service |
||||||
|
* manager. |
||||||
|
*/ |
||||||
|
public void initialize( S serviceManager ); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service manager is started or if the |
||||||
|
* service is added to an already started service manager. |
||||||
|
*/ |
||||||
|
public void start(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the service is shutting down. All services |
||||||
|
* are stopped and any service manager resources are closed |
||||||
|
* before the services are terminated. |
||||||
|
*/ |
||||||
|
public void stop(); |
||||||
|
|
||||||
|
/** |
||||||
|
* The service manager is fully shutting down. All services |
||||||
|
* have been stopped and related connections closed. |
||||||
|
*/ |
||||||
|
public void terminate( S serviceManager ); |
||||||
|
} |
@ -0,0 +1,160 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.concurrent.CopyOnWriteArrayList; |
||||||
|
|
||||||
|
/** |
||||||
|
* The base service manager class from which the HostedServiceManager |
||||||
|
* and ClientServiceManager classes are derived. This manages the |
||||||
|
* the underlying services and their life cycles. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public abstract class ServiceManager<T> { |
||||||
|
|
||||||
|
private List<Service<T>> services = new CopyOnWriteArrayList<Service<T>>(); |
||||||
|
private volatile boolean started = false; |
||||||
|
|
||||||
|
protected ServiceManager() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retreives the 'parent' of this service manager, usually |
||||||
|
* a more specifically typed version of 'this' but it can be |
||||||
|
* anything the seervices are expecting. |
||||||
|
*/ |
||||||
|
protected abstract T getParent(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the complete list of services managed by this |
||||||
|
* service manager. This list is thread safe following the |
||||||
|
* CopyOnWriteArrayList semantics. |
||||||
|
*/ |
||||||
|
protected List<Service<T>> getServices() { |
||||||
|
return services; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Starts this service manager and all services that it contains. |
||||||
|
* Any services added after the service manager has started will have |
||||||
|
* their start() methods called. |
||||||
|
*/ |
||||||
|
public void start() { |
||||||
|
if( started ) { |
||||||
|
return; |
||||||
|
} |
||||||
|
for( Service<T> s : services ) { |
||||||
|
s.start(); |
||||||
|
} |
||||||
|
started = true; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true if this service manager has been started. |
||||||
|
*/ |
||||||
|
public boolean isStarted() { |
||||||
|
return started; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Stops all services and puts the service manager into a stopped state. |
||||||
|
*/ |
||||||
|
public void stop() { |
||||||
|
if( !started ) { |
||||||
|
throw new IllegalStateException(getClass().getSimpleName() + " not started."); |
||||||
|
} |
||||||
|
for( Service<T> s : services ) { |
||||||
|
s.stop(); |
||||||
|
} |
||||||
|
started = false; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the specified service and initializes it. If the service manager |
||||||
|
* has already been started then the service will also be started. |
||||||
|
*/ |
||||||
|
public <S extends Service<T>> void addService( S s ) { |
||||||
|
services.add(s); |
||||||
|
s.initialize(getParent()); |
||||||
|
if( started ) { |
||||||
|
s.start(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes the specified service from this service manager, stopping |
||||||
|
* and terminating it as required. If this service manager is in a |
||||||
|
* started state then the service will be stopped. After removal, |
||||||
|
* the service will be terminated. |
||||||
|
*/ |
||||||
|
public <S extends Service<T>> void removeService( S s ) { |
||||||
|
if( started ) { |
||||||
|
s.stop(); |
||||||
|
} |
||||||
|
services.remove(s); |
||||||
|
s.terminate(getParent()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Terminates all services. If the service manager has not been |
||||||
|
* stopped yet then it will be stopped. |
||||||
|
*/ |
||||||
|
public void terminate() { |
||||||
|
if( started ) { |
||||||
|
stop(); |
||||||
|
} |
||||||
|
for( Service<T> s : services ) { |
||||||
|
s.terminate(getParent()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the first service of the specified type. |
||||||
|
*/ |
||||||
|
public <S extends Service<T>> S getService( Class<S> type ) { |
||||||
|
for( Service s : services ) { |
||||||
|
if( type.isInstance(s) ) { |
||||||
|
return type.cast(s); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getClass().getName() + "[services=" + services + "]"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,123 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc; |
||||||
|
|
||||||
|
import com.jme3.network.Client; |
||||||
|
import com.jme3.network.util.ObjectMessageDelegator; |
||||||
|
import com.jme3.network.service.AbstractClientService; |
||||||
|
import com.jme3.network.service.ClientServiceManager; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* RPC service that can be added to a network Client to |
||||||
|
* add RPC send/receive capabilities. Remote procedure |
||||||
|
* calls can be made to the server and responses retrieved. |
||||||
|
* Any remote procedure calls that the server performs for |
||||||
|
* this connection will be received by this service and delegated |
||||||
|
* to the appropriate RpcHandlers. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public class RpcClientService extends AbstractClientService { |
||||||
|
|
||||||
|
private RpcConnection rpc; |
||||||
|
private ObjectMessageDelegator delegator; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new RpcClientService that can be registered |
||||||
|
* with the network Client object. |
||||||
|
*/ |
||||||
|
public RpcClientService() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to setup the RpcConnection and MessageDelegator. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void onInitialize( ClientServiceManager serviceManager ) { |
||||||
|
Client client = serviceManager.getClient(); |
||||||
|
this.rpc = new RpcConnection(client); |
||||||
|
|
||||||
|
delegator = new ObjectMessageDelegator(rpc, true); |
||||||
|
client.addMessageListener(delegator, delegator.getMessageTypes()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to unregister the RPC MessageDelegator that |
||||||
|
* was previously added to the network Client. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void terminate( ClientServiceManager serviceManager ) { |
||||||
|
Client client = serviceManager.getClient(); |
||||||
|
client.removeMessageListener(delegator, delegator.getMessageTypes()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a synchronous call on the server against the specified |
||||||
|
* object using the specified procedure ID. Both inboud and outbound |
||||||
|
* communication is done on the specified channel. |
||||||
|
*/ |
||||||
|
public Object callAndWait( byte channel, short objId, short procId, Object... args ) { |
||||||
|
return rpc.callAndWait(channel, objId, procId, args); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs an asynchronous call on the server against the specified |
||||||
|
* object using the specified procedure ID. Communication is done |
||||||
|
* over the specified channel. No responses are received and none |
||||||
|
* are waited for. |
||||||
|
*/ |
||||||
|
public void callAsync( byte channel, short objId, short procId, Object... args ) { |
||||||
|
rpc.callAsync(channel, objId, procId, args); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Register a handler that will be called when the server |
||||||
|
* performs a remove procedure call against this client. |
||||||
|
* Only one handler per object ID can be registered at any given time, |
||||||
|
* though the same handler can be registered for multiple object |
||||||
|
* IDs. |
||||||
|
*/ |
||||||
|
public void registerHandler( short objId, RpcHandler handler ) { |
||||||
|
rpc.registerHandler(objId, handler); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a previously registered handler for the specified |
||||||
|
* object ID. |
||||||
|
*/ |
||||||
|
public void removeHandler( short objId, RpcHandler handler ) { |
||||||
|
rpc.removeHandler(objId, handler); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,247 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc; |
||||||
|
|
||||||
|
import com.jme3.network.MessageConnection; |
||||||
|
import com.jme3.network.service.rpc.msg.RpcCallMessage; |
||||||
|
import com.jme3.network.service.rpc.msg.RpcResponseMessage; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
import java.util.concurrent.atomic.AtomicLong; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Wraps a message connection to provide RPC call support. This |
||||||
|
* is used internally by the RpcClientService and RpcHostedService to manage |
||||||
|
* network messaging. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public class RpcConnection { |
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(RpcConnection.class.getName()); |
||||||
|
|
||||||
|
/** |
||||||
|
* The underlying connection upon which RPC call messages are sent |
||||||
|
* and RPC response messages are received. It can be a Client or |
||||||
|
* a HostedConnection depending on the mode of the RPC service. |
||||||
|
*/ |
||||||
|
private MessageConnection connection; |
||||||
|
|
||||||
|
/** |
||||||
|
* The objectId index of RpcHandler objects that are used to perform the |
||||||
|
* RPC calls for a particular object. |
||||||
|
*/ |
||||||
|
private Map<Short, RpcHandler> handlers = new ConcurrentHashMap<Short, RpcHandler>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Provides unique messages IDs for outbound synchronous call |
||||||
|
* messages. These are then used in the responses index to |
||||||
|
* locate the proper ResponseHolder objects. |
||||||
|
*/ |
||||||
|
private AtomicLong sequenceNumber = new AtomicLong(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Tracks the ResponseHolder objects for sent message IDs. When the |
||||||
|
* response is received, the appropriate handler is found here and the |
||||||
|
* response or error set, thus releasing the waiting caller. |
||||||
|
*/ |
||||||
|
private Map<Long, ResponseHolder> responses = new ConcurrentHashMap<Long, ResponseHolder>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new RpcConnection for the specified network connection. |
||||||
|
*/ |
||||||
|
public RpcConnection( MessageConnection connection ) { |
||||||
|
this.connection = connection; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Clears any pending synchronous calls causing them to |
||||||
|
* throw an exception with the message "Closing connection". |
||||||
|
*/ |
||||||
|
public void close() { |
||||||
|
// Let any pending waits go free
|
||||||
|
for( ResponseHolder holder : responses.values() ) { |
||||||
|
holder.release(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a remote procedure call with the specified arguments and waits |
||||||
|
* for the response. Both the outbound message and inbound response will |
||||||
|
* be sent on the specified channel. |
||||||
|
*/ |
||||||
|
public Object callAndWait( byte channel, short objId, short procId, Object... args ) { |
||||||
|
|
||||||
|
RpcCallMessage msg = new RpcCallMessage(sequenceNumber.getAndIncrement(), |
||||||
|
channel, objId, procId, args); |
||||||
|
|
||||||
|
// Need to register an object so we can wait for the response.
|
||||||
|
// ...before we send it. Just in case.
|
||||||
|
ResponseHolder holder = new ResponseHolder(msg); |
||||||
|
responses.put(msg.getMessageId(), holder); |
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "Sending:{0} on channel:{1}", new Object[]{msg, channel}); |
||||||
|
} |
||||||
|
connection.send(channel, msg); |
||||||
|
|
||||||
|
return holder.getResponse(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Performs a remote procedure call with the specified arguments but does |
||||||
|
* not wait for a response. The outbound message is sent on the specified channel. |
||||||
|
* There is no inbound response message. |
||||||
|
*/ |
||||||
|
public void callAsync( byte channel, short objId, short procId, Object... args ) { |
||||||
|
|
||||||
|
RpcCallMessage msg = new RpcCallMessage(-1, channel, objId, procId, args); |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "Sending:{0} on channel:{1}", new Object[]{msg, channel}); |
||||||
|
} |
||||||
|
connection.send(channel, msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Register a handler that can be called by the other end |
||||||
|
* of the connection using the specified object ID. Only one |
||||||
|
* handler per object ID can be registered at any given time, |
||||||
|
* though the same handler can be registered for multiple object |
||||||
|
* IDs. |
||||||
|
*/ |
||||||
|
public void registerHandler( short objId, RpcHandler handler ) { |
||||||
|
handlers.put(objId, handler); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a previously registered handler for the specified |
||||||
|
* object ID. |
||||||
|
*/ |
||||||
|
public void removeHandler( short objId, RpcHandler handler ) { |
||||||
|
RpcHandler removing = handlers.get(objId); |
||||||
|
if( handler != removing ) { |
||||||
|
throw new IllegalArgumentException("Handler not registered for object ID:" |
||||||
|
+ objId + ", handler:" + handler ); |
||||||
|
} |
||||||
|
handlers.remove(objId); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when an RpcCallMessage is received from |
||||||
|
* the remote connection. |
||||||
|
*/ |
||||||
|
public void handleMessage( RpcCallMessage msg ) { |
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "handleMessage({0})", msg); |
||||||
|
} |
||||||
|
RpcHandler handler = handlers.get(msg.getObjectId()); |
||||||
|
try { |
||||||
|
Object result = handler.call(this, msg.getObjectId(), msg.getProcedureId(), msg.getArguments()); |
||||||
|
if( !msg.isAsync() ) { |
||||||
|
RpcResponseMessage response = new RpcResponseMessage(msg.getMessageId(), result); |
||||||
|
connection.send(msg.getChannel(), response); |
||||||
|
} |
||||||
|
} catch( Exception e ) { |
||||||
|
if( !msg.isAsync() ) { |
||||||
|
RpcResponseMessage response = new RpcResponseMessage(msg.getMessageId(), e); |
||||||
|
connection.send(msg.getChannel(), response); |
||||||
|
} else { |
||||||
|
log.log(Level.SEVERE, "Error invoking async call for:" + msg, e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when an RpcResponseMessage is received from |
||||||
|
* the remote connection. |
||||||
|
*/ |
||||||
|
public void handleMessage( RpcResponseMessage msg ) { |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "handleMessage({0})", msg); |
||||||
|
} |
||||||
|
ResponseHolder holder = responses.remove(msg.getMessageId()); |
||||||
|
if( holder == null ) { |
||||||
|
return; |
||||||
|
} |
||||||
|
holder.setResponse(msg); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sort of like a Future, holds a locked reference to a response |
||||||
|
* until the remote call has completed and returned a response. |
||||||
|
*/ |
||||||
|
private class ResponseHolder { |
||||||
|
private Object response; |
||||||
|
private String error; |
||||||
|
private RpcCallMessage msg; |
||||||
|
boolean received = false; |
||||||
|
|
||||||
|
public ResponseHolder( RpcCallMessage msg ) { |
||||||
|
this.msg = msg; |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void setResponse( RpcResponseMessage msg ) { |
||||||
|
this.response = msg.getResult(); |
||||||
|
this.error = msg.getError(); |
||||||
|
this.received = true; |
||||||
|
notifyAll(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized Object getResponse() { |
||||||
|
try { |
||||||
|
while(!received) { |
||||||
|
wait(); |
||||||
|
} |
||||||
|
} catch( InterruptedException e ) { |
||||||
|
throw new RuntimeException("Interrupted waiting for respone to:" + msg, e); |
||||||
|
} |
||||||
|
if( error != null ) { |
||||||
|
throw new RuntimeException("Error calling remote procedure:" + msg + "\n" + error); |
||||||
|
} |
||||||
|
return response; |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void release() { |
||||||
|
if( received ) { |
||||||
|
return; |
||||||
|
} |
||||||
|
// Else signal an error for the callers
|
||||||
|
this.error = "Closing connection"; |
||||||
|
this.received = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Implementations of this interface can be registered with |
||||||
|
* the RpcClientService or RpcHostService to handle the |
||||||
|
* remote procedure calls for a given object or objects. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public interface RpcHandler { |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when a remote procedure call request is received for a particular |
||||||
|
* object from the other end of the network connection. |
||||||
|
*/ |
||||||
|
public Object call( RpcConnection conn, short objectId, short procId, Object... args ); |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -0,0 +1,227 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc; |
||||||
|
|
||||||
|
import com.jme3.network.HostedConnection; |
||||||
|
import com.jme3.network.Server; |
||||||
|
import com.jme3.network.serializing.Serializer; |
||||||
|
import com.jme3.network.util.SessionDataDelegator; |
||||||
|
import com.jme3.network.service.AbstractHostedService; |
||||||
|
import com.jme3.network.service.HostedServiceManager; |
||||||
|
import com.jme3.network.service.rpc.msg.RpcCallMessage; |
||||||
|
import com.jme3.network.service.rpc.msg.RpcResponseMessage; |
||||||
|
import java.util.Arrays; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* RPC service that can be added to a network Server to |
||||||
|
* add RPC send/receive capabilities. For a particular |
||||||
|
* HostedConnection, Remote procedure calls can be made to the |
||||||
|
* associated Client and responses retrieved. Any remote procedure |
||||||
|
* calls that the Client performs for this connection will be |
||||||
|
* received by this service and delegated to the appropriate RpcHandlers. |
||||||
|
* |
||||||
|
* Note: it can be dangerous for a server to perform synchronous |
||||||
|
* RPC calls to a client but especially so if not done as part |
||||||
|
* of the response to some other message. ie: iterating over all |
||||||
|
* or some HostedConnections to perform synchronous RPC calls |
||||||
|
* will be slow and potentially block the server's threads in ways |
||||||
|
* that can cause deadlocks or odd contention. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
public class RpcHostedService extends AbstractHostedService { |
||||||
|
|
||||||
|
private static final String ATTRIBUTE_NAME = "rpcSession"; |
||||||
|
|
||||||
|
static final Logger log = Logger.getLogger(RpcHostedService.class.getName()); |
||||||
|
|
||||||
|
private boolean autoHost; |
||||||
|
private SessionDataDelegator delegator; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new RPC host service that can be registered |
||||||
|
* with the Network server and will automatically 'host' |
||||||
|
* RPC services and each new network connection. |
||||||
|
*/ |
||||||
|
public RpcHostedService() { |
||||||
|
this(true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new RPC host service that can be registered |
||||||
|
* with the Network server and will optionally 'host' |
||||||
|
* RPC services and each new network connection depending |
||||||
|
* on the specified 'autoHost' flag. |
||||||
|
*/ |
||||||
|
public RpcHostedService( boolean autoHost ) { |
||||||
|
this.autoHost = autoHost; |
||||||
|
|
||||||
|
// This works for me... has to be different in
|
||||||
|
// the general case
|
||||||
|
Serializer.registerClasses(RpcCallMessage.class, RpcResponseMessage.class); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to setup the message delegator that will |
||||||
|
* handle HostedConnection specific messages and forward them |
||||||
|
* to that connection's RpcConnection. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected void onInitialize( HostedServiceManager serviceManager ) { |
||||||
|
Server server = serviceManager.getServer(); |
||||||
|
|
||||||
|
// A general listener for forwarding the messages
|
||||||
|
// to the client-specific handler
|
||||||
|
this.delegator = new SessionDataDelegator(RpcConnection.class, |
||||||
|
ATTRIBUTE_NAME, |
||||||
|
true); |
||||||
|
server.addMessageListener(delegator, delegator.getMessageTypes()); |
||||||
|
|
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "Registered delegator for message types:{0}", Arrays.asList(delegator.getMessageTypes())); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* When set to true, all new connections will automatically have |
||||||
|
* RPC hosting services attached to them, meaning they can send |
||||||
|
* and receive RPC calls. If this is set to false then it is up |
||||||
|
* to other services to eventually call startHostingOnConnection(). |
||||||
|
* |
||||||
|
* <p>Reasons for doing this vary but usually would be because |
||||||
|
* the client shouldn't be allowed to perform any RPC calls until |
||||||
|
* it has provided more information. In general, this is unnecessary |
||||||
|
* because the RpcHandler registries are not shared. Each client |
||||||
|
* gets their own and RPC calls will fail until the appropriate |
||||||
|
* objects have been registtered.</p> |
||||||
|
*/ |
||||||
|
public void setAutoHost( boolean b ) { |
||||||
|
this.autoHost = b; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns true if this service automatically attaches RPC |
||||||
|
* hosting capabilities to new connections. |
||||||
|
*/ |
||||||
|
public boolean getAutoHost() { |
||||||
|
return autoHost; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Retrieves the RpcConnection for the specified HostedConnection |
||||||
|
* if that HostedConnection has had RPC services started using |
||||||
|
* startHostingOnConnection() (or via autohosting). Returns null |
||||||
|
* if the connection currently doesn't have RPC hosting services |
||||||
|
* attached. |
||||||
|
*/ |
||||||
|
public RpcConnection getRpcConnection( HostedConnection hc ) { |
||||||
|
return hc.getAttribute(ATTRIBUTE_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets up RPC hosting services for the hosted connection allowing |
||||||
|
* getRpcConnection() to return a valid RPC connection object. |
||||||
|
* This method is called automatically for all new connections if |
||||||
|
* autohost is set to true. |
||||||
|
*/ |
||||||
|
public void startHostingOnConnection( HostedConnection hc ) { |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "startHostingOnConnection:{0}", hc); |
||||||
|
} |
||||||
|
hc.setAttribute(ATTRIBUTE_NAME, new RpcConnection(hc)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes any RPC hosting services associated with the specified |
||||||
|
* connection. Calls to getRpcConnection() will return null for |
||||||
|
* this connection. The connection's RpcConnection is also closed, |
||||||
|
* releasing any waiting synchronous calls with a "Connection closing" |
||||||
|
* error. |
||||||
|
* This method is called automatically for all leaving connections if |
||||||
|
* autohost is set to true. |
||||||
|
*/ |
||||||
|
public void stopHostingOnConnection( HostedConnection hc ) { |
||||||
|
RpcConnection rpc = hc.getAttribute(ATTRIBUTE_NAME); |
||||||
|
if( rpc == null ) { |
||||||
|
return; |
||||||
|
} |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "stopHostingOnConnection:{0}", hc); |
||||||
|
} |
||||||
|
hc.setAttribute(ATTRIBUTE_NAME, null); |
||||||
|
rpc.close(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to remove the message delegator from the |
||||||
|
* server. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void terminate(HostedServiceManager serviceManager) { |
||||||
|
Server server = serviceManager.getServer(); |
||||||
|
server.removeMessageListener(delegator, delegator.getMessageTypes()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when a new connection is detected for |
||||||
|
* the server. If the current autoHost property is true then |
||||||
|
* startHostingOnConnection(hc) is called. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void connectionAdded(Server server, HostedConnection hc) { |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "connectionAdded({0}, {1})", new Object[]{server, hc}); |
||||||
|
} |
||||||
|
if( autoHost ) { |
||||||
|
startHostingOnConnection(hc); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called internally when an existing connection is leaving |
||||||
|
* the server. If the current autoHost property is true then |
||||||
|
* stopHostingOnConnection(hc) is called. |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void connectionRemoved(Server server, HostedConnection hc) { |
||||||
|
if( log.isLoggable(Level.FINEST) ) { |
||||||
|
log.log(Level.FINEST, "connectionRemoved({0}, {1})", new Object[]{server, hc}); |
||||||
|
} |
||||||
|
stopHostingOnConnection(hc); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,98 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc.msg; |
||||||
|
|
||||||
|
import com.jme3.network.AbstractMessage; |
||||||
|
import com.jme3.network.serializing.Serializable; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to send RPC call information to |
||||||
|
* the other end of a connection for execution. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
@Serializable |
||||||
|
public class RpcCallMessage extends AbstractMessage { |
||||||
|
|
||||||
|
private long msgId; |
||||||
|
private byte channel; |
||||||
|
private short objId; |
||||||
|
private short procId; |
||||||
|
private Object[] args; |
||||||
|
|
||||||
|
public RpcCallMessage() { |
||||||
|
} |
||||||
|
|
||||||
|
public RpcCallMessage( long msgId, byte channel, short objId, short procId, Object... args ) { |
||||||
|
this.msgId = msgId; |
||||||
|
this.channel = channel; |
||||||
|
this.objId = objId; |
||||||
|
this.procId = procId; |
||||||
|
this.args = args; |
||||||
|
} |
||||||
|
|
||||||
|
public long getMessageId() { |
||||||
|
return msgId; |
||||||
|
} |
||||||
|
|
||||||
|
public byte getChannel() { |
||||||
|
return channel; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isAsync() { |
||||||
|
return msgId == -1; |
||||||
|
} |
||||||
|
|
||||||
|
public short getObjectId() { |
||||||
|
return objId; |
||||||
|
} |
||||||
|
|
||||||
|
public short getProcedureId() { |
||||||
|
return procId; |
||||||
|
} |
||||||
|
|
||||||
|
public Object[] getArguments() { |
||||||
|
return args; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getClass().getSimpleName() + "[#" + msgId + ", channel=" + channel |
||||||
|
+ (isAsync() ? ", async" : ", sync") |
||||||
|
+ ", objId=" + objId |
||||||
|
+ ", procId=" + procId |
||||||
|
+ ", args.length=" + args.length |
||||||
|
+ "]"; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
/* |
||||||
|
* Copyright (c) 2015 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.service.rpc.msg; |
||||||
|
|
||||||
|
import com.jme3.network.AbstractMessage; |
||||||
|
import com.jme3.network.serializing.Serializable; |
||||||
|
import java.io.PrintWriter; |
||||||
|
import java.io.StringWriter; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally to send an RPC call's response back to |
||||||
|
* the caller. |
||||||
|
* |
||||||
|
* @author Paul Speed |
||||||
|
*/ |
||||||
|
@Serializable |
||||||
|
public class RpcResponseMessage extends AbstractMessage { |
||||||
|
|
||||||
|
private long msgId; |
||||||
|
private Object result; |
||||||
|
private String error; |
||||||
|
|
||||||
|
public RpcResponseMessage() { |
||||||
|
} |
||||||
|
|
||||||
|
public RpcResponseMessage( long msgId, Object result ) { |
||||||
|
this.msgId = msgId; |
||||||
|
this.result = result; |
||||||
|
} |
||||||
|
|
||||||
|
public RpcResponseMessage( long msgId, Throwable t ) { |
||||||
|
this.msgId = msgId; |
||||||
|
|
||||||
|
StringWriter sOut = new StringWriter(); |
||||||
|
PrintWriter out = new PrintWriter(sOut); |
||||||
|
t.printStackTrace(out); |
||||||
|
out.close(); |
||||||
|
this.error = sOut.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public long getMessageId() { |
||||||
|
return msgId; |
||||||
|
} |
||||||
|
|
||||||
|
public Object getResult() { |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public String getError() { |
||||||
|
return error; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
return getClass().getSimpleName() + "[#" + msgId + ", result=" + result |
||||||
|
+ "]"; |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue