/* * JBoss, Home of Professional Open Source. * Copyright 2011, 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.domain.controller.operations.coordination; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.FAILURE_DESCRIPTION; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.RESULT; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVERS; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.SERVER_OPERATIONS; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.TransformingProxyController; import org.jboss.as.controller.transform.OperationResultTransformer; import org.jboss.as.controller.transform.OperationTransformer; import org.jboss.as.controller.transform.Transformers; import org.jboss.as.domain.controller.LocalHostControllerInfo; import org.jboss.as.domain.controller.ServerIdentity; import org.jboss.as.domain.controller.logging.DomainControllerLogger; import org.jboss.dmr.ModelNode; import org.jboss.dmr.Property; /** * Stores overall contextual information for a multi-phase operation executing on the domain. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ public final class MultiphaseOverallContext { private final LocalHostControllerInfo localHostInfo; private final MultiPhaseLocalContext localContext = new MultiPhaseLocalContext(true); private final ConcurrentMap<String, ModelNode> hostControllerPreparedResults = new ConcurrentHashMap<String, ModelNode>(); private final ConcurrentMap<String, ModelNode> hostControllerFinalResults = new ConcurrentHashMap<String, ModelNode>(); private final ConcurrentMap<ServerIdentity, ModelNode> serverResults = new ConcurrentHashMap<ServerIdentity, ModelNode>(); private final ConcurrentMap<String, HostControllerUpdateTask.ExecutedHostRequest> finalResultFutures = new ConcurrentHashMap<String, HostControllerUpdateTask.ExecutedHostRequest>(); private final Map<String, Boolean> serverGroupStatuses = new ConcurrentHashMap<String, Boolean>(); private volatile boolean completeRollback = true; private volatile boolean failureReported; MultiphaseOverallContext(final LocalHostControllerInfo localHostInfo) { this.localHostInfo = localHostInfo; } LocalHostControllerInfo getLocalHostInfo() { return localHostInfo; } MultiPhaseLocalContext getLocalContext() { return localContext; } Map<String, ModelNode> getHostControllerPreparedResults() { return new HashMap<String, ModelNode>(hostControllerPreparedResults); } void addHostControllerPreparedResult(String hostId, ModelNode hostResult) { hostControllerPreparedResults.put(hostId, hostResult); } Map<String, ModelNode> getHostControllerFinalResults() { return new HashMap<String, ModelNode>(hostControllerFinalResults); } void addHostControllerFinalResult(String hostId, ModelNode hostResult) { hostControllerFinalResults.put(hostId, hostResult); } Map<ServerIdentity, ModelNode> getServerResults() { return new HashMap<ServerIdentity, ModelNode>(serverResults); } void addServerResult(ServerIdentity serverId, ModelNode serverResult) { serverResults.put(serverId, serverResult); } boolean isCompleteRollback() { return completeRollback; } public void setCompleteRollback(boolean completeRollback) { this.completeRollback = completeRollback; } boolean isServerGroupRollback(String serverGroup) { Boolean ok = serverGroupStatuses.get(serverGroup); return ok == null || ok.booleanValue(); } public void setServerGroupRollback(String serverGroup, boolean rollback) { serverGroupStatuses.put(serverGroup, rollback); } public boolean hasHostLevelFailures() { ModelNode coordinatorResult = localContext.getLocalResponse(); boolean domainFailed = coordinatorResult.isDefined() && coordinatorResult.has(FAILURE_DESCRIPTION); if (domainFailed) { return true; } for (ModelNode hostResult : hostControllerPreparedResults.values()) { if (hostResult.has(FAILURE_DESCRIPTION)) { return true; } } return false; } public boolean isFailureReported() { return failureReported; } public void setFailureReported(boolean failureReported) { this.failureReported = failureReported; } public ModelNode getServerResult(String hostName, String serverName, String... stepLabels) { ModelNode result; ServerIdentity id = new ServerIdentity(hostName, null, serverName); ModelNode serverResult = getServerResults().get(id); if (serverResult == null) { return null; } serverResult = serverResult.clone(); if (stepLabels.length == 0) { result = serverResult; } else { result = new ModelNode(); ModelNode hostResults; if (hostName.equals(localHostInfo.getLocalHostName())) { hostResults = new ModelNode(); hostResults.get(RESULT, SERVER_OPERATIONS).set(localContext.getLocalServerOps()); } else { hostResults = hostControllerPreparedResults.get(hostName); } String[] translatedSteps = getTranslatedSteps(serverName, hostResults, stepLabels); if (translatedSteps != null && serverResult.hasDefined(translatedSteps)) { if (DomainControllerLogger.HOST_CONTROLLER_LOGGER.isTraceEnabled()) { DomainControllerLogger.HOST_CONTROLLER_LOGGER.tracef("Translated steps for %s/%s[%s] are %s", hostName, serverName, Arrays.asList(stepLabels), Arrays.asList(translatedSteps)); } result.set(serverResult.get(translatedSteps)); } } return result; } /* * Transform an operation for a server. This will also delegate to the host-controller result-transformer. */ public OperationTransformer.TransformedOperation transformServerOperation(final String hostName, final TransformingProxyController remoteProxyController, final Transformers.TransformationInputs transformationInputs, final ModelNode original) throws OperationFailedException { final OperationTransformer.TransformedOperation transformed = remoteProxyController.transformOperation(transformationInputs, original); final HostControllerUpdateTask.ExecutedHostRequest hostRequest = finalResultFutures.get(hostName); if(hostRequest == null) { // in case it's local hosts-controller return transformed; } return new OperationTransformer.TransformedOperation(transformed.getTransformedOperation(), new OperationResultTransformer() { @Override public ModelNode transformResult(ModelNode result) { final ModelNode step1 = transformed.transformResult(result); return hostRequest.transformResult(step1); } }); } protected void recordHostRequest(final String hostName, final HostControllerUpdateTask.ExecutedHostRequest request) { finalResultFutures.put(hostName, request); } private String[] getTranslatedSteps(String serverName, ModelNode hostResults, String[] stepLabels) { String[] result = null; ModelNode domainMappedOp = getDomainMappedOperation(serverName, hostResults); if (domainMappedOp != null) { result = new String[stepLabels.length * 2]; ModelNode level = domainMappedOp; for (int i = 0; i < stepLabels.length; i++) { String translated = getTranslatedStepIndex(stepLabels[i], level); if (translated == null) { return null; } result[i * 2] = RESULT; result[(i * 2) + 1] = translated; level = level.get(stepLabels[i]); } } return result; } private String getTranslatedStepIndex(String stepLabel, ModelNode level) { int i = 1; for (String key : level.keys()) { if (stepLabel.equals(key)) { return "step-" + i; } i++; } return null; } private ModelNode getDomainMappedOperation(String serverName, ModelNode hostResults) { for (ModelNode set : hostResults.get(RESULT, SERVER_OPERATIONS).asList()) { for (Property prop : set.get(SERVERS).asPropertyList()) { if (prop.getName().equals(serverName)) { return set.get(OP); } } } return null; } }