Adding an initial implementation for a service manager module
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.
This commit is contained in:
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…
x
Reference in New Issue
Block a user