/* * Copyright 2016 JBoss by Red Hat. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.as.server.jmx; import static org.jboss.as.controller.client.helpers.ClientConstants.CONTROLLER_PROCESS_STATE_OK; import static org.wildfly.extension.core.management.client.Process.Type.DOMAIN_SERVER; import static org.wildfly.extension.core.management.client.Process.Type.EMBEDDED_SERVER; import static org.wildfly.extension.core.management.client.Process.Type.STANDALONE_SERVER; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.lang.management.ManagementFactory; import java.util.concurrent.atomic.AtomicLong; import javax.management.AttributeChangeNotification; import javax.management.MBeanNotificationInfo; import javax.management.MBeanServer; import javax.management.NotificationBroadcasterSupport; import javax.management.ObjectName; import org.jboss.as.controller.ControlledProcessState; import org.jboss.as.controller.ControlledProcessStateService; import org.jboss.as.controller.RunningModeControl; import org.jboss.as.server.logging.ServerLogger; import org.jboss.as.server.suspend.OperationListener; import org.jboss.as.server.suspend.SuspendController; import org.wildfly.extension.core.management.client.Process.RunningState; import org.wildfly.extension.core.management.client.Process.RuntimeConfigurationState; import org.wildfly.extension.core.management.client.Process.RunningMode; import org.wildfly.extension.core.management.client.Process.Type; /** * * @author Emmanuel Hugonnet (c) 2016 Red Hat, inc. */ public class RunningStateJmx extends NotificationBroadcasterSupport implements RunningStateJmxMBean { private final ObjectName objectName; private final AtomicLong sequence = new AtomicLong(0); private volatile RuntimeConfigurationState state = RuntimeConfigurationState.STOPPED; private volatile RunningState runningState = RunningState.STOPPED; private volatile RunningModeControl runningModeControl = null; private final boolean isServer; public static final String RUNTIME_CONFIGURATION_STATE = "RuntimeConfigurationState"; public static final String RUNNING_STATE = "RunningState"; private RunningStateJmx(ObjectName objectName, RunningModeControl runningModeControl, Type type) { this.objectName = objectName; this.runningModeControl = runningModeControl; this.isServer = type == DOMAIN_SERVER || type == EMBEDDED_SERVER || type == STANDALONE_SERVER; } @Override public String getProcessState() { return state.toString(); } @Override public RunningState getRunningState() { return runningState; } @Override public RunningMode getRunningMode() { return RunningMode.from(runningModeControl.getRunningMode().name()); } @Override public MBeanNotificationInfo[] getNotificationInfo() { return new MBeanNotificationInfo[]{ new MBeanNotificationInfo( new String[]{AttributeChangeNotification.ATTRIBUTE_CHANGE}, AttributeChangeNotification.class.getName(), ServerLogger.ROOT_LOGGER.processStateChangeNotificationDescription())}; } @Override public synchronized void setProcessState(ControlledProcessState.State oldState, ControlledProcessState.State newState) { final String stateString; if (newState == ControlledProcessState.State.RUNNING) { stateString = CONTROLLER_PROCESS_STATE_OK; } else { stateString = newState.toString(); } final String oldStateString; if (oldState == ControlledProcessState.State.RUNNING) { oldStateString = CONTROLLER_PROCESS_STATE_OK; } else { oldStateString = oldState.toString(); } this.state = RuntimeConfigurationState.valueOf(newState.name()); AttributeChangeNotification notification = new AttributeChangeNotification(objectName, sequence.getAndIncrement(), System.currentTimeMillis(), ServerLogger.ROOT_LOGGER.jmxAttributeChange(RUNTIME_CONFIGURATION_STATE, oldStateString, stateString), RUNTIME_CONFIGURATION_STATE, String.class.getName(), oldStateString, stateString); sendNotification(notification); switch(newState) { case RUNNING: if (RunningState.NORMAL != runningState && RunningState.ADMIN_ONLY != runningState && !isServer) { if (getRunningMode() == RunningMode.NORMAL) { setRunningState(runningState, RunningState.NORMAL); } else { setRunningState(runningState, RunningState.ADMIN_ONLY); } } break; case STARTING: if (RunningState.STARTING != runningState) { setRunningState(runningState, RunningState.STARTING); } break; case STOPPING: if (RunningState.STOPPING != runningState) { setRunningState(runningState, RunningState.STOPPING); } break; case STOPPED: if (RunningState.STOPPED != runningState) { setRunningState(runningState, RunningState.STOPPED); } break; case RELOAD_REQUIRED: case RESTART_REQUIRED: default: } } @Override public synchronized void setRunningState(RunningState oldState, RunningState newState) { if(oldState == null || oldState == newState || this.runningState == newState) { return; } this.runningState = newState; AttributeChangeNotification notification = new AttributeChangeNotification(objectName, sequence.getAndIncrement(), System.currentTimeMillis(), ServerLogger.ROOT_LOGGER.jmxAttributeChange(RUNNING_STATE, oldState.toString(), newState.toString()), RUNNING_STATE, String.class.getName(), oldState.toString(), newState.toString()); sendNotification(notification); } public static void registerMBean(ControlledProcessStateService processStateService, SuspendController suspendController, RunningModeControl runningModeControl, Type type) { try { final ObjectName name = new ObjectName(OBJECT_NAME); final MBeanServer server = ManagementFactory.getPlatformMBeanServer(); final RunningStateJmxMBean mbean = new RunningStateJmx(name, runningModeControl, type); if (server.isRegistered(name)) { server.unregisterMBean(name); } server.registerMBean(mbean, name); registerStateListener(mbean, processStateService); if (suspendController != null) { suspendController.addListener(new OperationListener() { @Override public void suspendStarted() { mbean.setRunningState(mbean.getRunningState(), RunningState.SUSPENDING); } @Override public void complete() { mbean.setRunningState(mbean.getRunningState(), RunningState.SUSPENDED); } @Override public void cancelled() { if(mbean.getRunningState() == null || mbean.getRunningState() == RunningState.STARTING) { mbean.setRunningState(RunningState.STARTING, RunningState.SUSPENDED); } if (mbean.getRunningMode() == RunningMode.NORMAL) { mbean.setRunningState(mbean.getRunningState(), RunningState.NORMAL); } else { mbean.setRunningState(mbean.getRunningState(),RunningState.ADMIN_ONLY); } } @Override public void timeout() { } }); } else { mbean.setRunningState(null, RunningState.STARTING); } } catch (Exception e) { throw new RuntimeException(e); } } private static void registerStateListener(RunningStateJmxMBean mbean, ControlledProcessStateService processStateService) { processStateService.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("currentState".equals(evt.getPropertyName())) { ControlledProcessState.State oldState = (ControlledProcessState.State) evt.getOldValue(); ControlledProcessState.State newState = (ControlledProcessState.State) evt.getNewValue(); mbean.setProcessState(oldState, newState); } } }); } }