/*
* 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;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 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> {
static final Logger log = Logger.getLogger(ServiceManager.class.getName());
private final 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 ) {
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Starting service:{0}", s);
}
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 ) {
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Stopping service:{0}", s);
}
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 ) {
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "addService({0})", s);
}
services.add(s);
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Initializing service:{0}", s);
}
s.initialize(getParent());
if( started ) {
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Starting service:{0}", s);
}
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( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "removeService({0})", s);
}
if( started ) {
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Stopping service:{0}", s);
}
s.stop();
}
services.remove(s);
if( log.isLoggable(Level.FINE) ) {
log.log(Level.FINE, "Terminating service:{0}", 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 + "]";
}
}