/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, Red Hat, Inc., and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.as.clustering.msc;
import java.util.EnumMap;
import java.util.EnumSet;
import java.util.Map;
import org.jboss.msc.service.ServiceController;
import org.jboss.msc.service.ServiceController.Mode;
import org.jboss.msc.service.ServiceController.State;
import org.jboss.msc.service.ServiceName;
import org.jboss.msc.service.ServiceRegistry;
import org.jboss.msc.service.StabilityMonitor;
import org.jboss.msc.service.StartException;
/**
* Helper methods for interacting with a modular service container.
* @author Paul Ferraro
* @author <a href="mailto:ropalka@redhat.com">Richard Opalka</a>
*/
public class ServiceContainerHelper {
// Mapping of service controller mode changes that appropriate for toggling to a given controller state
private static final Map<State, Map<Mode, Mode>> modeToggle = new EnumMap<>(State.class);
static {
Map<Mode, Mode> map = new EnumMap<>(Mode.class);
map.put(Mode.NEVER, Mode.ACTIVE);
map.put(Mode.ON_DEMAND, Mode.PASSIVE);
modeToggle.put(State.UP, map);
map = new EnumMap<>(Mode.class);
map.put(Mode.ACTIVE, Mode.NEVER);
map.put(Mode.PASSIVE, Mode.ON_DEMAND);
modeToggle.put(State.DOWN, map);
map = new EnumMap<>(Mode.class);
for (Mode mode: EnumSet.complementOf(EnumSet.of(Mode.REMOVE))) {
map.put(mode, Mode.REMOVE);
}
modeToggle.put(State.REMOVED, map);
}
/**
* Returns the value of the specified service, if the service exists and is started.
* @param registry the service registry
* @param name the service name
* @return the service value, if the service exists and is started, null otherwise
*/
public static <T> T findValue(ServiceRegistry registry, ServiceName name) {
ServiceController<T> service = findService(registry, name);
return ((service != null) && (service.getState() == State.UP)) ? service.getValue() : null;
}
/**
* Generics friendly version of {@link ServiceRegistry#getService(ServiceName)}
* @param registry service registry
* @param name service name
* @return the service controller with the specified name, or null if the service does not exist
*/
public static <T> ServiceController<T> findService(ServiceRegistry registry, ServiceName name) {
return (ServiceController<T>) registry.getService(name);
}
/**
* Generics friendly version of {@link ServiceRegistry#getRequiredService(ServiceName)}
* @param registry service registry
* @param name service name
* @return the service controller with the specified name
* @throws org.jboss.msc.ServiceNotFoundException if the service was not found
*/
public static <T> ServiceController<T> getService(ServiceRegistry registry, ServiceName name) {
return (ServiceController<T>) registry.getRequiredService(name);
}
/**
* Returns the service value of the specified service, starting it if necessary.
* @param controller a service controller
* @return the service value of the specified service
* @throws StartException if the specified service could not be started
*/
public static <T> T getValue(ServiceController<T> controller) throws StartException {
start(controller);
return controller.getValue();
}
/**
* Ensures the specified service is started.
* @param controller a service controller
* @throws StartException if the specified service could not be started
*/
public static <T> void start(final ServiceController<T> controller) throws StartException {
transition(controller, State.UP);
StartException exception = controller.getStartException();
if (exception != null) {
throw exception;
}
}
/**
* Ensures the specified service is stopped.
* @param controller a service controller
*/
public static <T> void stop(ServiceController<T> controller) {
transition(controller, State.DOWN);
}
/**
* Ensures the specified service is removed.
* @param controller a service controller
*/
public static <T> void remove(ServiceController<T> controller) {
transition(controller, State.REMOVED);
}
private static <T> void transition(final ServiceController<T> targetController, final State targetState) {
// Short-circuit if the service is already at the target state
if (targetController.getState() == targetState) return;
StabilityMonitor monitor = new StabilityMonitor();
monitor.addController(targetController);
try {
// Force service to transition to desired state
Mode targetMode = modeToggle.get(targetState).get(targetController.getMode());
if (targetMode != null) {
targetController.setMode(targetMode);
}
monitor.awaitStability();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
monitor.removeController(targetController);
}
}
private ServiceContainerHelper() {
// Hide
}
}