/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, 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.host.controller.mgmt; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OPERATION_HEADERS; import java.io.File; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.as.controller.CurrentOperationIdHolder; import org.jboss.as.controller.ModelController; import org.jboss.as.controller.OperationContext; import org.jboss.as.controller.OperationFailedException; import org.jboss.as.controller.OperationStepHandler; import org.jboss.as.controller.client.Operation; import org.jboss.as.controller.client.OperationMessageHandler; import org.jboss.as.controller.client.OperationResponse; import org.jboss.as.controller.remote.AbstractModelControllerOperationHandlerFactoryService; import org.jboss.as.controller.remote.ModelControllerClientOperationHandler; import org.jboss.as.controller.remote.ModelControllerClientOperationHandlerFactoryService; import org.jboss.as.controller.remote.ResponseAttachmentInputStreamSupport; import org.jboss.as.controller.remote.TransactionalProtocolOperationHandler; import org.jboss.as.domain.controller.DomainController; import org.jboss.as.domain.controller.HostRegistrations; import org.jboss.as.domain.controller.operations.FetchMissingConfigurationHandler; import org.jboss.as.domain.controller.operations.coordination.DomainControllerLockIdUtils; import org.jboss.as.host.controller.logging.HostControllerLogger; import org.jboss.as.protocol.mgmt.ManagementChannelAssociation; import org.jboss.as.protocol.mgmt.ManagementChannelHandler; import org.jboss.as.protocol.mgmt.ManagementClientChannelStrategy; import org.jboss.as.protocol.mgmt.ManagementPongRequestHandler; import org.jboss.as.protocol.mgmt.ManagementRequestContext; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.jboss.remoting3.Channel; /** * Installs {@link MasterDomainControllerOperationHandlerImpl} which handles requests from slave DC to master DC. * * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> */ public class MasterDomainControllerOperationHandlerService extends AbstractModelControllerOperationHandlerFactoryService { public static final ServiceName SERVICE_NAME = DomainController.SERVICE_NAME.append(ModelControllerClientOperationHandlerFactoryService.OPERATION_HANDLER_NAME_SUFFIX); private final DomainController domainController; private final HostControllerRegistrationHandler.OperationExecutor operationExecutor; private final TransactionalOperationExecutor txOperationExecutor; private final ManagementPongRequestHandler pongRequestHandler = new ManagementPongRequestHandler(); private final File tempDir; private final HostRegistrations slaveHostRegistrations; private final DomainHostExcludeRegistry domainHostExcludeRegistry; public MasterDomainControllerOperationHandlerService(final DomainController domainController, final HostControllerRegistrationHandler.OperationExecutor operationExecutor, TransactionalOperationExecutor txOperationExecutor, final File tempDir, final HostRegistrations slaveHostRegistrations, DomainHostExcludeRegistry domainHostExcludeRegistry) { this.domainController = domainController; this.operationExecutor = operationExecutor; this.txOperationExecutor = txOperationExecutor; this.tempDir = tempDir; this.slaveHostRegistrations = slaveHostRegistrations; this.domainHostExcludeRegistry = domainHostExcludeRegistry; } @Override public synchronized void start(StartContext context) throws StartException { pongRequestHandler.resetConnectionId(); super.start(context); } @Override public ManagementChannelHandler startReceiving(final Channel channel) { final ManagementChannelHandler handler = new ManagementChannelHandler(ManagementClientChannelStrategy.create(channel), getExecutor()); handler.getAttachments().attach(ManagementChannelHandler.TEMP_DIR, tempDir); // Assemble the request handlers for the domain channel handler.addHandlerFactory(new HostControllerRegistrationHandler(handler, domainController, operationExecutor, getExecutor(), slaveHostRegistrations, domainHostExcludeRegistry)); handler.addHandlerFactory(new ModelControllerClientOperationHandler(getController(), handler, getResponseAttachmentSupport(), getClientRequestExecutor())); handler.addHandlerFactory(new MasterDomainControllerOperationHandlerImpl(domainController, getExecutor())); handler.addHandlerFactory(pongRequestHandler); handler.addHandlerFactory(new DomainTransactionalProtocolOperationHandler(txOperationExecutor, handler, getResponseAttachmentSupport())); channel.receiveMessage(handler.getReceiver()); return handler; } private class DomainTransactionalProtocolOperationHandler extends TransactionalProtocolOperationHandler { private final TransactionalOperationExecutor executor; private volatile SlaveRequest activeSlaveRequest; public DomainTransactionalProtocolOperationHandler(TransactionalOperationExecutor executor, ManagementChannelAssociation channelAssociation, ResponseAttachmentInputStreamSupport responseAttachmentSupport) { super(null, channelAssociation, responseAttachmentSupport); this.executor = executor; } @Override protected OperationResponse internalExecute(final Operation operation, final ManagementRequestContext<?> context, final OperationMessageHandler messageHandler, final ModelController.OperationTransactionControl control) { final ModelNode operationNode = operation.getOperation(); final OperationStepHandler handler; final String operationName = operation.getOperation().require(OP).asString(); if (operationName.equals(FetchMissingConfigurationHandler.OPERATION_NAME)) { handler = new FetchMissingConfigurationHandler(SlaveChannelAttachments.getHostName(context.getChannel()), SlaveChannelAttachments.getTransformers(context.getChannel()), domainController.getExtensionRegistry()); } else { throw HostControllerLogger.ROOT_LOGGER.cannotExecuteTransactionalOperationFromSlave(operationName); } Integer domainControllerLockId; if (operationNode.get(OPERATION_HEADERS).hasDefined(DomainControllerLockIdUtils.DOMAIN_CONTROLLER_LOCK_ID)) { domainControllerLockId = operationNode.get(OPERATION_HEADERS, DomainControllerLockIdUtils.DOMAIN_CONTROLLER_LOCK_ID).asInt(); } else { domainControllerLockId = null; } if (domainControllerLockId == null) { synchronized (this) { SlaveRequest slaveRequest = this.activeSlaveRequest; if (slaveRequest != null) { domainControllerLockId = slaveRequest.domainId; slaveRequest.refCount.incrementAndGet(); } } } try { if (domainControllerLockId != null) { assert operation.getInputStreams().size() == 0; // we don't support associating streams with an active op ModelNode responseNode = executor.joinActiveOperation(operation.getOperation(), messageHandler, control, handler, domainControllerLockId); return OperationResponse.Factory.createSimple(responseNode); } else { return executor.executeAndAttemptLock(operation, messageHandler, control, new OperationStepHandler() { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { //Grab the lock id and store it Integer domainControllerLockId = CurrentOperationIdHolder.getCurrentOperationID(); synchronized (this) { activeSlaveRequest = new SlaveRequest(domainControllerLockId); } context.addStep(operation, handler, OperationContext.Stage.MODEL); } }); } } finally { synchronized (this) { SlaveRequest slaveRequest = this.activeSlaveRequest; if (slaveRequest != null) { int refcount = slaveRequest.refCount.decrementAndGet(); if (refcount == 0) { activeSlaveRequest = null; } } } } } } public interface TransactionalOperationExecutor { OperationResponse executeAndAttemptLock(Operation operation, OperationMessageHandler handler, ModelController.OperationTransactionControl control, OperationStepHandler step); ModelNode joinActiveOperation(ModelNode operation, OperationMessageHandler handler, ModelController.OperationTransactionControl control, OperationStepHandler step, int permit); } private final class SlaveRequest { private final int domainId; private final AtomicInteger refCount = new AtomicInteger(1); SlaveRequest(int domainId){ this.domainId = domainId; } } }