/* * 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.controller; import java.io.InputStream; import java.util.List; import java.util.Set; import java.util.function.Supplier; import org.jboss.as.controller.access.Action; import org.jboss.as.controller.access.AuthorizationResult; import org.jboss.as.controller.access.ResourceAuthorization; import org.jboss.as.controller.audit.AuditLogger; import org.jboss.as.controller.capability.CapabilityServiceSupport; import org.jboss.as.controller.capability.RuntimeCapability; import org.jboss.as.controller.client.MessageSeverity; import org.jboss.as.controller.logging.ControllerLogger; import org.jboss.as.controller.notification.Notification; import org.jboss.as.controller.persistence.ConfigurationPersistenceException; import org.jboss.as.controller.persistence.ConfigurationPersister; import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.Resource; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceRegistry; import org.jboss.msc.service.ServiceTarget; import org.wildfly.security.auth.server.SecurityIdentity; /** * {@link OperationContext} implementation for parallel handling of subsystem operations during boot. * * @author Brian Stansberry (c) 2011 Red Hat Inc. */ @SuppressWarnings("deprecation") class ParallelBootOperationContext extends AbstractOperationContext { private final OperationContextImpl primaryContext; private final List<ParsedBootOp> runtimeOps; private Step lockStep; private final int operationId; private final ModelControllerImpl controller; ParallelBootOperationContext(final ModelController.OperationTransactionControl transactionControl, final ControlledProcessState processState, final OperationContextImpl primaryContext, final List<ParsedBootOp> runtimeOps, final Thread controllingThread, final ModelControllerImpl controller, final int operationId, final AuditLogger auditLogger, final Resource model, final OperationStepHandler extraValidationStepHandler, final Supplier<SecurityIdentity> securityIdentitySupplier) { super(primaryContext.getProcessType(), primaryContext.getRunningMode(), transactionControl, processState, true, auditLogger, controller.getNotificationSupport(), controller, true, extraValidationStepHandler, securityIdentitySupplier); this.primaryContext = primaryContext; this.runtimeOps = runtimeOps; AbstractOperationContext.controllingThread.set(controllingThread); // this.controller = controller; this.operationId = operationId; } void close() { AbstractOperationContext.controllingThread.remove(); } @Override public void addStep(OperationStepHandler step, Stage stage) throws IllegalArgumentException { if (activeStep == null) { throw ControllerLogger.ROOT_LOGGER.noActiveStep(); } addStep(activeStep.response, activeStep.operation, step, stage); } @Override public void addStep(ModelNode operation, OperationStepHandler step, Stage stage) throws IllegalArgumentException { if (activeStep == null) { throw ControllerLogger.ROOT_LOGGER.noActiveStep(); } addStep(activeStep.response, operation, step, stage); } @Override public void addStep(ModelNode operation, OperationStepHandler step, Stage stage, final boolean addFirst) throws IllegalArgumentException { if (activeStep == null) { throw ControllerLogger.ROOT_LOGGER.noActiveStep(); } addStep(activeStep.response, operation, step, stage, addFirst); } @Override public void addStep(ModelNode response, ModelNode operation, OperationStepHandler step, Stage stage) throws IllegalArgumentException { switch (stage) { case MODEL: super.addStep(response, operation, step, stage); break; case RUNTIME: if (runtimeOps != null) { // Cache for use by the runtime step from ParallelBootOperationStepHandler ParsedBootOp parsedOp = new ParsedBootOp(operation, step, response); runtimeOps.add(parsedOp); } else { super.addStep(response, operation, step, stage); } break; default: // Handle VERIFY in the primary context, after parallel work is done primaryContext.addStep(response, operation, step, stage); } } // Methods unimplemented by superclass @Override ModelControllerImpl.ManagementModelImpl getManagementModel() { throw new IllegalStateException(); // Wrong usage, we cannot guarantee thread safety } @Override public InputStream getAttachmentStream(int index) { return primaryContext.getAttachmentStream(index); } @Override public int getAttachmentStreamCount() { return primaryContext.getAttachmentStreamCount(); } @Override public boolean isRollbackOnRuntimeFailure() { return primaryContext.isRollbackOnRuntimeFailure(); } @Override public boolean isResourceServiceRestartAllowed() { return primaryContext.isResourceServiceRestartAllowed(); } @Override public ImmutableManagementResourceRegistration getResourceRegistration() { ImmutableManagementResourceRegistration parent = primaryContext.getResourceRegistration(); return parent.getSubModel(activeStep.address); } @Override public ManagementResourceRegistration getResourceRegistrationForUpdate() { acquireControllerLock(); ManagementResourceRegistration parent = primaryContext.getResourceRegistrationForUpdate(); return parent.getSubModel(activeStep.address); } @Override public ImmutableManagementResourceRegistration getRootResourceRegistration() { return primaryContext.getRootResourceRegistration(); } @Override public ServiceRegistry getServiceRegistry(boolean modify) throws UnsupportedOperationException { if(modify) { acquireControllerLock(); } return primaryContext.getServiceRegistry(modify, activeStep); } @Override public ServiceController<?> removeService(ServiceName name) throws UnsupportedOperationException { acquireControllerLock(); return primaryContext.removeService(name); } @Override public void removeService(ServiceController<?> controller) throws UnsupportedOperationException { acquireControllerLock(); primaryContext.removeService(controller); } @Override public ServiceTarget getServiceTarget() throws UnsupportedOperationException { acquireControllerLock(); return primaryContext.getServiceTarget(activeStep); } @Override public void acquireControllerLock() { if(lockStep == null) { try { controller.acquireWriteLock(operationId, true); lockStep = activeStep; } catch (InterruptedException e) { cancelled = true; Thread.currentThread().interrupt(); throw ControllerLogger.ROOT_LOGGER.operationCancelledAsynchronously(); } } } @Override public Resource createResource(PathAddress address) throws UnsupportedOperationException { acquireControllerLock(); PathAddress fullAddress = activeStep.address.append(address); return primaryContext.createResource(fullAddress); } @Override public void addResource(PathAddress address, Resource toAdd) { acquireControllerLock(); PathAddress fullAddress = activeStep.address.append(address); primaryContext.addResource(fullAddress, toAdd); } @Override public void addResource(PathAddress address, int index, Resource toAdd) { acquireControllerLock(); PathAddress fullAddress = activeStep.address.append(address); primaryContext.addResource(fullAddress, index, toAdd); } @Override public Resource readResource(PathAddress address) { return readResource(address, true); } @Override public Resource readResource(PathAddress address, boolean recursive) { PathAddress fullAddress = activeStep.address.append(address); return primaryContext.readResource(fullAddress, recursive); } @Override public Resource readResourceFromRoot(PathAddress address) { return readResourceFromRoot(address, true); } @Override public Resource readResourceFromRoot(PathAddress address, boolean recursive) { return primaryContext.readResourceFromRoot(address, recursive); } @Override protected Resource readResourceFromRoot(ManagementModel model, PathAddress address, boolean recursive) { return primaryContext.readResourceFromRoot(model, address, recursive); } @Override public Resource readResourceForUpdate(PathAddress address) { acquireControllerLock(); PathAddress fullAddress = activeStep.address.append(address); return primaryContext.readResourceForUpdate(fullAddress); } @Override public Resource removeResource(PathAddress address) throws UnsupportedOperationException { acquireControllerLock(); PathAddress fullAddress = activeStep.address.append(address); return primaryContext.removeResource(fullAddress); } @Override public Resource getOriginalRootResource() { return primaryContext.getOriginalRootResource(); } @Override public boolean isModelAffected() { return primaryContext.isModelAffected(); } @Override public boolean isResourceRegistryAffected() { return primaryContext.isResourceRegistryAffected(); } @Override public boolean isRuntimeAffected() { return primaryContext.isRuntimeAffected(); } @Override public Stage getCurrentStage() { return primaryContext.getCurrentStage(); } @Override public void report(MessageSeverity severity, String message) { primaryContext.report(severity, message); } @Override public boolean markResourceRestarted(PathAddress resource, Object owner) { throw new UnsupportedOperationException("Resource restarting is not supported during boot"); } @Override public boolean revertResourceRestarted(PathAddress resource, Object owner) { throw new UnsupportedOperationException("Resource restarting is not supported during boot"); } @Override void awaitServiceContainerStability() throws InterruptedException { // ignored } @Override ConfigurationPersister.PersistenceResource createPersistenceResource() throws ConfigurationPersistenceException { // We don't persist return null; } @Override void publishCapabilityRegistry() { //we don't publish anything } @Override void operationRollingBack() { // BES 2015/06/30 hmm. telling the primary context to discarding the management model // here will screw up other parallel contexts that are still running. but if we don't, // during rollback our OSHs will still see the changes made to the model. // Oh well, I'm not going to worry about it as this runs in boot, and a rollback in // boot should just result in the whole process going away anyway. } @Override public void emit(Notification notification) { primaryContext.emit(notification); } @Override public void registerCapability(RuntimeCapability capability, String attribute) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.registerCapability(capability, activeStep, attribute); } @Override public void registerCapability(RuntimeCapability capability) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.registerCapability(capability, activeStep, null); } @Override public void registerAdditionalCapabilityRequirement(String required, String dependent, String attribute) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.registerAdditionalCapabilityRequirement(required, dependent, activeStep, attribute); } @Override public boolean hasOptionalCapability(String required, String dependent, String attribute) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements return primaryContext.requestOptionalCapability(required, dependent, true, activeStep, attribute); } @Override public void requireOptionalCapability(String required, String dependent, String attribute) throws OperationFailedException { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.requireOptionalCapability(required, dependent, activeStep, attribute); } @Override public void deregisterCapabilityRequirement(String required, String dependent) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.removeCapabilityRequirement(required, dependent, activeStep); } @Override public void deregisterCapability(String capability) { // pass in the step we are executing so it can be failed if there is problem resolving capabilities/requirements primaryContext.removeCapability(capability, activeStep); } @Override public <T> T getCapabilityRuntimeAPI(String capabilityName, Class<T> apiType) { return primaryContext.getCapabilityRuntimeAPI(capabilityName, apiType, activeStep); } @Override public <T> T getCapabilityRuntimeAPI(String capabilityBaseName, String dynamicPart, Class<T> apiType) { return primaryContext.getCapabilityRuntimeAPI(RuntimeCapability.buildDynamicCapabilityName(capabilityBaseName, dynamicPart), apiType, activeStep); } @Override public ServiceName getCapabilityServiceName(String capabilityName, Class<?> type) { return primaryContext.getCapabilityServiceName(capabilityName, type, activeStep); } @Override public ServiceName getCapabilityServiceName(String capabilityBaseName, String dynamicPart, Class<?> serviceType) { return primaryContext.getCapabilityServiceName(RuntimeCapability.buildDynamicCapabilityName(capabilityBaseName, dynamicPart), serviceType, activeStep); } @Override public CapabilityServiceSupport getCapabilityServiceSupport() { return primaryContext.getCapabilityServiceSupport(); } @Override void releaseStepLocks(Step step) { if(lockStep == step) { controller.releaseWriteLock(operationId); lockStep = null; } } @Override void waitForRemovals() { // nothing to do } @Override boolean isReadOnly() { return primaryContext.isReadOnly(); } @Override ManagementResourceRegistration getRootResourceRegistrationForUpdate() { return primaryContext.getRootResourceRegistrationForUpdate(); } @Override public ModelNode resolveExpressions(ModelNode node) throws OperationFailedException { return primaryContext.resolveExpressions(node); } @Override public <T> T getAttachment(final AttachmentKey<T> key) { return primaryContext.getAttachment(key); } @Override public <T> T attach(final AttachmentKey<T> key, final T value) { return primaryContext.attach(key, value); } @Override public <T> T attachIfAbsent(final AttachmentKey<T> key, final T value) { return primaryContext.attachIfAbsent(key, value); } @Override public <T> T detach(final AttachmentKey<T> key) { return primaryContext.detach(key); } @Override public AuthorizationResult authorize(ModelNode operation) { return primaryContext.authorize(operation); } @Override public AuthorizationResult authorize(ModelNode operation, Set<Action.ActionEffect> effects) { return primaryContext.authorize(operation, effects); } @Override public AuthorizationResult authorize(ModelNode operation, String attribute, ModelNode currentValue) { return primaryContext.authorize(operation, attribute, currentValue); } @Override public AuthorizationResult authorize(ModelNode operation, String attribute, ModelNode currentValue, Set<Action.ActionEffect> effects) { return primaryContext.authorize(operation, attribute, currentValue, effects); } @Override public AuthorizationResult authorizeOperation(ModelNode operation) { return primaryContext.authorizeOperation(operation); } @Override public ResourceAuthorization authorizeResource(boolean attributes, boolean isDefaultResource) { return primaryContext.authorizeResource(attributes, isDefaultResource); } Resource getModel() { return primaryContext.getModel(); } @Override void logAuditRecord() { // handled by the primary context } }