/* * JBoss, Home of Professional Open Source. * Copyright 2011, 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.model.test; import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicReference; import org.jboss.as.controller.AbstractControllerService; import org.jboss.as.controller.CapabilityRegistry; import org.jboss.as.controller.CompositeOperationHandler; import org.jboss.as.controller.ControlledProcessState; import org.jboss.as.controller.ExpressionResolver; import org.jboss.as.controller.ManagementModel; 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.PathAddress; import org.jboss.as.controller.PathElement; import org.jboss.as.controller.ProcessType; import org.jboss.as.controller.ResourceDefinition; import org.jboss.as.controller.RunningMode; import org.jboss.as.controller.RunningModeControl; import org.jboss.as.controller.access.management.AccessConstraintDefinition; import org.jboss.as.controller.access.management.DelegatingConfigurableAuthorizer; import org.jboss.as.controller.access.management.ManagementSecurityIdentitySupplier; import org.jboss.as.controller.audit.AuditLogger; import org.jboss.as.controller.client.OperationAttachments; import org.jboss.as.controller.client.OperationMessageHandler; import org.jboss.as.controller.descriptions.DescriptionProvider; import org.jboss.as.controller.operations.global.GlobalOperationHandlers; import org.jboss.as.controller.operations.validation.OperationValidator; import org.jboss.as.controller.persistence.ConfigurationPersistenceException; import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration; import org.jboss.as.controller.registry.ManagementResourceRegistration; import org.jboss.as.controller.registry.Resource; import org.jboss.as.controller.transform.TransformerRegistry; import org.jboss.dmr.ModelNode; import org.jboss.msc.service.StartContext; import org.jboss.msc.service.StartException; import org.junit.Assert; /** * Internal class used by test framework.Boots up the model controller used for the test. * While the super class {@link AbstractControllerService} exists here in the main code source, for the legacy controllers it is got from the * xxxx/test-controller-xxx jars instead (see the constructor javadocs for more information) * * @author <a href="kabir.khan@jboss.com">Kabir Khan</a> * @author Tomaz Cerar */ //TODO find better way to support legacy ModelTestModelControllerService without need for having all old methods still present on AbstractControllerService public abstract class ModelTestModelControllerService extends AbstractControllerService { private final CountDownLatch latch = new CountDownLatch(1); private final StringConfigurationPersister persister; private final TransformerRegistry transformerRegistry; private final ModelTestOperationValidatorFilter validateOpsFilter; private final RunningModeControl runningModeControl; private volatile ManagementResourceRegistration rootRegistration; private volatile Throwable error; private volatile boolean bootSuccess; /** * This is the constructor to use for core-model/test-controller-7.3.x */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DelegatingResourceDefinition rootResourceDefinition, ControlledProcessState processState, Controller73x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootResourceDefinition, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for subsystem-test/test-controller-7.3.x */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DescriptionProvider rootDescriptionProvider, ControlledProcessState processState, Controller73x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootDescriptionProvider, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for core-model/test-controller-7.4.x */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DelegatingResourceDefinition rootResourceDefinition, ControlledProcessState processState, Controller74x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootResourceDefinition, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for subsystem-test/test-controller-7.4.x */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DescriptionProvider rootDescriptionProvider, ControlledProcessState processState, Controller74x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootDescriptionProvider, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 8.0.x core model tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DelegatingResourceDefinition rootResourceDefinition, ControlledProcessState processState, ExpressionResolver expressionResolver, Controller80x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootResourceDefinition, null, expressionResolver, AuditLogger.NO_OP_LOGGER, new DelegatingConfigurableAuthorizer()); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 8.0.x subsystem tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final ResourceDefinition resourceDefinition, ControlledProcessState processState, Controller80x version) { // Fails in core-model-test transformation testing if ExpressionResolver.TEST_RESOLVER is used because not present in 7.1.x super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, resourceDefinition, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 9.0.x core model tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DelegatingResourceDefinition rootResourceDefinition, ControlledProcessState processState, ExpressionResolver expressionResolver, Controller90x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootResourceDefinition, null, expressionResolver, AuditLogger.NO_OP_LOGGER, new DelegatingConfigurableAuthorizer()); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 9.0.x subsystem tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final ResourceDefinition resourceDefinition, ControlledProcessState processState, Controller90x version) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, resourceDefinition, null, ExpressionResolver.TEST_RESOLVER); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 2.x core model tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final DelegatingResourceDefinition rootResourceDefinition, ControlledProcessState processState, ExpressionResolver expressionResolver, CapabilityRegistry capabilityRegistry) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, rootResourceDefinition, null, expressionResolver, AuditLogger.NO_OP_LOGGER, new DelegatingConfigurableAuthorizer(), new ManagementSecurityIdentitySupplier(), capabilityRegistry); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } /** * This is the constructor to use for 10.x subsystem tests */ protected ModelTestModelControllerService(final ProcessType processType, final RunningModeControl runningModeControl, final TransformerRegistry transformerRegistry, final StringConfigurationPersister persister, final ModelTestOperationValidatorFilter validateOpsFilter, final ResourceDefinition resourceDefinition, ControlledProcessState processState, final CapabilityRegistry capabilityRegistry) { super(processType, runningModeControl, persister, processState == null ? new ControlledProcessState(true) : processState, resourceDefinition, null, ExpressionResolver.TEST_RESOLVER, AuditLogger.NO_OP_LOGGER, new DelegatingConfigurableAuthorizer(), new ManagementSecurityIdentitySupplier(), capabilityRegistry); this.persister = persister; this.transformerRegistry = transformerRegistry; this.validateOpsFilter = validateOpsFilter; this.runningModeControl = runningModeControl; } public boolean isSuccessfulBoot() { return bootSuccess; } public Throwable getBootError() { return error; } RunningMode getRunningMode() { return runningModeControl.getRunningMode(); } ProcessType getProcessType() { return processType; } @Override protected void initModel(ManagementModel managementModel, Resource modelControllerResource) { this.rootRegistration = managementModel.getRootResourceRegistration(); initCoreModel(managementModel, modelControllerResource); initExtraModel(managementModel); } /** @deprecated only for legacy version support */ @Deprecated protected void initModel(Resource rootResource, ManagementResourceRegistration rootRegistration, Resource modelControllerResource) { this.rootRegistration = rootRegistration; initCoreModel(rootResource, rootRegistration, modelControllerResource); initExtraModel(rootResource, rootRegistration); } @SuppressWarnings("deprecation") protected void initCoreModel(ManagementModel managementModel, Resource modelControllerResource) { initCoreModel(managementModel.getRootResource(), managementModel.getRootResourceRegistration(), modelControllerResource); } /** @deprecated only for legacy version support */ @Deprecated protected void initCoreModel(Resource rootResource, ManagementResourceRegistration rootRegistration, Resource modelControllerResource) { GlobalOperationHandlers.registerGlobalOperations(rootRegistration, ProcessType.STANDALONE_SERVER); rootRegistration.registerOperationHandler(CompositeOperationHandler.DEFINITION, CompositeOperationHandler.INSTANCE); //we don't register notifications as eap 6.2 and 6.3 dont support it, this is done in each legacy controller separatly } @SuppressWarnings("deprecation") protected void initExtraModel(ManagementModel managementModel) { initExtraModel(managementModel.getRootResource(), managementModel.getRootResourceRegistration()); } /** @deprecated only for legacy version support */ @Deprecated protected void initExtraModel(Resource rootResource, ManagementResourceRegistration rootRegistration) { } TransformerRegistry getTransformersRegistry() { return transformerRegistry; } @Override protected boolean boot(List<ModelNode> bootOperations, boolean rollbackOnRuntimeFailure) throws ConfigurationPersistenceException { try { preBoot(bootOperations, rollbackOnRuntimeFailure); // See what we need to validate, but defer doing it to after super.boot to allow // initModel to run first and given tests a chance to set things up List<ModelNode> validationList = new ArrayList<>(); for (ModelNode op : bootOperations) { ModelNode toValidate = validateOpsFilter.adjustForValidation(op.clone()); if (toValidate != null) { validationList.add(toValidate); } } bootSuccess = super.boot(persister.getBootOperations(), rollbackOnRuntimeFailure); // Ok, now we can validate OperationValidator validator = new OperationValidator(rootRegistration); for (ModelNode op : validationList) { validator.validateOperation(op); } return bootSuccess; } catch (Exception e) { error = e; } catch (Throwable t) { error = new Exception(t); } finally { postBoot(); } return false; } protected void preBoot(List<ModelNode> bootOperations, boolean rollbackOnRuntimeFailure) { } protected void postBoot() { } @Override protected void bootThreadDone() { try { super.bootThreadDone(); } finally { countdownDoneLatch(); } } protected void countdownDoneLatch() { latch.countDown(); } @Override public void start(StartContext context) throws StartException { try { super.start(context); } catch (StartException e) { error = e; e.printStackTrace(); latch.countDown(); throw e; } catch (Throwable t) { error = t; latch.countDown(); throw new StartException(t); } } public void waitForSetup() throws Exception { latch.await(); if (error != null) { if (error instanceof Exception) throw (Exception) error; throw new RuntimeException(error); } } public ManagementResourceRegistration getRootRegistration() { return rootRegistration; } /** * Grabs the current root resource. This cannot be called after the kernelServices * have been shut down * * @param kernelServices the kernel services used to access the controller */ public static Resource grabRootResource(ModelTestKernelServices<?> kernelServices) { final AtomicReference<Resource> resourceRef = new AtomicReference<Resource>(); ModelNode fakeOP = new ModelNode(); fakeOP.get(OP).set("fake"); ((ModelTestKernelServicesImpl<?>)kernelServices).internalExecute(fakeOP, new OperationStepHandler() { @Override public void execute(OperationContext context, ModelNode operation) throws OperationFailedException { resourceRef.set(context.readResourceFromRoot(PathAddress.EMPTY_ADDRESS, true)); context.getResult().setEmptyObject(); } }); Resource rootResource = resourceRef.get(); Assert.assertNotNull(rootResource); return rootResource; } @SuppressWarnings("deprecation") @Override protected ModelNode internalExecute(final ModelNode operation, final OperationMessageHandler handler, final ModelController.OperationTransactionControl control, final OperationAttachments attachments, final OperationStepHandler prepareStep) { return super.internalExecute(operation, handler, control, attachments, prepareStep); } public static class DelegatingResourceDefinition implements ResourceDefinition { private volatile ResourceDefinition delegate; public void setDelegate(ResourceDefinition delegate) { this.delegate = delegate; } @Override public void registerOperations(ManagementResourceRegistration resourceRegistration) { delegate.registerOperations(resourceRegistration); } @Override public void registerChildren(ManagementResourceRegistration resourceRegistration) { delegate.registerChildren(resourceRegistration); } @Override public void registerAttributes(ManagementResourceRegistration resourceRegistration) { delegate.registerAttributes(resourceRegistration); } @Override public void registerNotifications(ManagementResourceRegistration resourceRegistration) { delegate.registerNotifications(resourceRegistration); } @Override public PathElement getPathElement() { return delegate.getPathElement(); } @Override public DescriptionProvider getDescriptionProvider(ImmutableManagementResourceRegistration resourceRegistration) { return delegate.getDescriptionProvider(resourceRegistration); } @Override public List<AccessConstraintDefinition> getAccessConstraints() { if (delegate == null) { return Collections.emptyList(); } return delegate.getAccessConstraints(); } @Override public boolean isRuntime() { return delegate.isRuntime(); } @Override public boolean isOrderedChild() { if (delegate == null) { return false; } return delegate.isOrderedChild(); } @Override public void registerCapabilities(ManagementResourceRegistration resourceRegistration) { delegate.registerCapabilities(resourceRegistration); } } //These are here to overload the constuctor used for the different legacy controllers public static class Controller73x { public static Controller73x INSTANCE = new Controller73x(); private Controller73x() { } } public static class Controller74x { public static Controller74x INSTANCE = new Controller74x(); private Controller74x() { } } public static class Controller80x { public static Controller80x INSTANCE = new Controller80x(); private Controller80x() { } } public static class Controller90x { public static Controller90x INSTANCE = new Controller90x(); private Controller90x() { } } public static class Controller10x { public static Controller10x INSTANCE = new Controller10x(); private Controller10x() { } } }