/*
* JBoss, Home of Professional Open Source.
* Copyright 2012, 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.test;
import java.util.Collections;
import org.jboss.as.controller.ExpressionResolver;
import org.jboss.as.controller.ModelVersion;
import org.jboss.as.controller.OperationContext;
import org.jboss.as.controller.OperationFailedException;
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.SimpleResourceDefinition;
import org.jboss.as.controller.descriptions.ModelDescriptionConstants;
import org.jboss.as.controller.descriptions.NonResolvingResourceDescriptionResolver;
import org.jboss.as.controller.registry.GlobalTransformerRegistry;
import org.jboss.as.controller.registry.ImmutableManagementResourceRegistration;
import org.jboss.as.controller.registry.ManagementResourceRegistration;
import org.jboss.as.controller.registry.OperationTransformerRegistry;
import org.jboss.as.controller.registry.Resource;
import org.jboss.as.controller.registry.Resource.ResourceEntry;
import org.jboss.as.controller.transform.AbstractOperationTransformer;
import org.jboss.as.controller.transform.OperationResultTransformer;
import org.jboss.as.controller.transform.OperationTransformer;
import org.jboss.as.controller.transform.ResourceTransformationContext;
import org.jboss.as.controller.transform.ResourceTransformer;
import org.jboss.as.controller.transform.TransformationContext;
import org.jboss.as.controller.transform.TransformationTarget;
import org.jboss.as.controller.transform.TransformationTargetImpl;
import org.jboss.as.controller.transform.TransformerRegistry;
import org.jboss.as.controller.transform.Transformers;
import org.jboss.as.controller.transform.TransformersLogger;
import org.jboss.as.controller.transform.TransformersSubRegistration;
import org.jboss.dmr.ModelNode;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* @author Emanuel Muckenhuber
*/
public class OperationTransformationTestCase {
private static final PathAddress TEST_DISCARD = PathAddress.pathAddress(PathElement.pathElement("test", "discard"));
private static final PathAddress TEST_NORMAL = PathAddress.pathAddress(PathElement.pathElement("test", "normal"));
private static final ModelNode subsystems = new ModelNode();
static {
// Same subsystem response
subsystems.add("test", "1.0.0");
subsystems.add("modcluster", "1.1");
subsystems.add("naming", "1.0");
subsystems.add("osgi", "1.0");
subsystems.add("pojo", "1.0");
subsystems.add("remoting", "1.1");
subsystems.add("resource-adapters", "1.1");
}
private final Resource resourceRoot = Resource.Factory.create();
private final GlobalTransformerRegistry registry = new GlobalTransformerRegistry();
private final ManagementResourceRegistration resourceRegistration = ManagementResourceRegistration.Factory.forProcessType(ProcessType.EMBEDDED_SERVER).createRegistration(ROOT);
private final OperationTransformer NOOP_TRANSFORMER = new OperationTransformer() {
@Override
public TransformedOperation transformOperation(TransformationContext context, PathAddress address, ModelNode operation) {
return new TransformedOperation(new ModelNode(), OperationResultTransformer.ORIGINAL_RESULT);
}
};
private final OperationTransformer OPERATION_TRANSFORMER = new OperationTransformer() {
@Override
public TransformedOperation transformOperation(TransformationContext context, PathAddress address, ModelNode operation) throws OperationFailedException {
final ModelNode transformed = operation.clone();
transformed.get("param1").set("value1");
return new TransformedOperation(transformed, OperationResultTransformer.ORIGINAL_RESULT);
}
};
@Before
public void setUp() {
registry.discardOperation(TEST_DISCARD, 1, 1, "discard");
registry.registerTransformer(TEST_NORMAL, 1, 2, "normal", OPERATION_TRANSFORMER);
}
@Test
public void testDiscardOperation() throws OperationFailedException {
final ModelNode operation = new ModelNode();
operation.get(ModelDescriptionConstants.OP).set("discard");
operation.get(ModelDescriptionConstants.OP_ADDR).set(TEST_DISCARD.toModelNode());
Assert.assertNull(transform(operation, 1, 1));
}
@Test
public void testBasicTransformation() throws OperationFailedException {
final ModelNode operation = new ModelNode();
operation.get(ModelDescriptionConstants.OP).set("normal");
operation.get(ModelDescriptionConstants.OP_ADDR).set(TEST_NORMAL.toModelNode());
final ModelNode transformed = transform(operation, 1, 2);
Assert.assertNotNull(transformed);
Assert.assertTrue(transformed.has("param1"));
Assert.assertEquals("value1", transformed.get("param1").asString());
}
@Test
public void testDefaultPolicy() throws OperationFailedException {
final ModelNode operation = new ModelNode();
operation.get(ModelDescriptionConstants.OP).set("normal");
operation.get(ModelDescriptionConstants.OP_ADDR).set(TEST_NORMAL.toModelNode());
final ModelNode transformed = transform(operation, 1, 1);
Assert.assertNotNull(transformed);
Assert.assertFalse(transformed.has("param1"));
}
@Test
public void testMergeSubTree() {
final PathAddress address = PathAddress.pathAddress(PathElement.pathElement("subsystem", "test"));
final OperationTransformerRegistry localRegistry = registry.create(ModelVersion.create(1, 0, 0), Collections.<PathAddress, ModelVersion>emptyMap());
OperationTransformerRegistry.OperationTransformerEntry entry = localRegistry.resolveOperationTransformer(address, "testing", null);
Assert.assertSame(OperationTransformerRegistry.FORWARD, entry);
registry.registerTransformer(address, 1, 0, "testing", NOOP_TRANSFORMER);
localRegistry.mergeSubsystem(registry, "test", ModelVersion.create(1, 0));
entry = localRegistry.resolveOperationTransformer(address, "testing", null);
Assert.assertNotNull(entry);
Assert.assertSame(NOOP_TRANSFORMER, entry.getTransformer());
}
@Test
public void testGetSubRegistry() {
final PathAddress profile = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.PROFILE));
final PathAddress address = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, "test"));
final OperationTransformer transformer = new AbstractOperationTransformer() {
@Override
protected ModelNode transform(TransformationContext context, PathAddress address, ModelNode operation) {
return operation;
}
};
final TransformerRegistry transformers = TransformerRegistry.Factory.create();
final TransformersSubRegistration subsystem = transformers.registerSubsystemTransformers("test", ModelVersion.create(1), ResourceTransformer.DEFAULT);
subsystem.registerOperationTransformer("test", transformer);
final OperationTransformerRegistry server = transformers.resolveServer(ModelVersion.create(1, 2, 3), subsystems);
Assert.assertNotNull(server);
Assert.assertEquals(transformer, server.resolveOperationTransformer(address, "test", null).getTransformer());
final OperationTransformerRegistry host = transformers.resolveHost(ModelVersion.create(1, 2, 3), subsystems);
Assert.assertNotNull(host);
Assert.assertNotSame(transformer, host.resolveOperationTransformer(address, "test", null).getTransformer());
Assert.assertEquals(transformer, host.resolveOperationTransformer(profile.append(address), "test", null).getTransformer());
}
@Test
public void testConcreteRegistry() throws Exception {
final PathElement one = PathElement.pathElement(ModelDescriptionConstants.EXTENSION, "org.test.one");
final PathElement two = PathElement.pathElement(ModelDescriptionConstants.EXTENSION, "org.test.two");
final Resource resource = Resource.Factory.create();
resource.registerChild(one, Resource.Factory.create());
resource.registerChild(two, Resource.Factory.create());
final TransformerRegistry transformers = TransformerRegistry.Factory.create();
transformers.getDomainRegistration(ModelVersion.create(1, 2)).registerSubResource(one, true);
transformers.getDomainRegistration(ModelVersion.create(1, 3)).registerSubResource(two, true);
final TransformationTarget target10 = create(transformers, ModelVersion.create(1, 0));
final Resource transformed10 = transform(target10, resource);
Assert.assertEquals(2, transformed10.getChildren(ModelDescriptionConstants.EXTENSION).size());
Assert.assertNotNull(transformed10.getChild(one));
Assert.assertNotNull(transformed10.getChild(one));
final TransformationTarget target12 = create(transformers, ModelVersion.create(1, 2));
final Resource transformed12 = transform(target12, resource);
Assert.assertEquals(1, transformed12.getChildren(ModelDescriptionConstants.EXTENSION).size());
Assert.assertNull(transformed12.getChild(one));
Assert.assertNotNull(transformed12.getChild(two));
final TransformationTarget target13 = create(transformers, ModelVersion.create(1, 3));
final Resource transformed13 = transform(target13, resource);
Assert.assertEquals(1, transformed13.getChildren(ModelDescriptionConstants.EXTENSION).size());
Assert.assertNull(transformed13.getChild(two));
Assert.assertNotNull(transformed13.getChild(one));
}
@Test
public void testAddSubsystem() throws Exception {
final ModelVersion subsystem = ModelVersion.create(1, 2);
final TransformerRegistry registry = TransformerRegistry.Factory.create();
TransformersSubRegistration sub = registry.registerSubsystemTransformers("test", subsystem, ResourceTransformer.DISCARD);
sub.registerOperationTransformer("test", OPERATION_TRANSFORMER);
final TransformationTarget host = create(registry, ModelVersion.create(1, 2, 3));
host.addSubsystemVersion("test", subsystem);
final PathAddress profile = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.PROFILE, "test"));
final PathAddress serverAddress = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.HOST, "test"), PathElement.pathElement(ModelDescriptionConstants.RUNNING_SERVER, "test"));
final PathAddress subsytemAddress = PathAddress.pathAddress(PathElement.pathElement(ModelDescriptionConstants.SUBSYSTEM, "test"));
final OperationTransformer profileTransformer = host.resolveTransformer(new MockTransformationContext(), profile.append(subsytemAddress), "test");
Assert.assertEquals(profileTransformer, OPERATION_TRANSFORMER);
final OperationTransformer serverTransformer = host.resolveTransformer(new MockTransformationContext(), serverAddress.append(subsytemAddress), "test");
Assert.assertEquals(serverTransformer, OPERATION_TRANSFORMER);
}
protected TransformationTarget create(final TransformerRegistry registry, ModelVersion version) {
return create(registry, version, TransformationTarget.TransformationTargetType.HOST);
}
protected TransformationTarget create(final TransformerRegistry registry, ModelVersion version, TransformationTarget.TransformationTargetType type) {
return TransformationTargetImpl.create(null, registry, version, Collections.<PathAddress, ModelVersion>emptyMap(), type);
}
protected Resource transform(final TransformationTarget target, final Resource root) throws OperationFailedException {
final Transformers transformers = Transformers.Factory.create(target);
final ResourceTransformationContext ctx = Transformers.Factory.create(target, root, resourceRegistration,
resolver, RunningMode.NORMAL, ProcessType.HOST_CONTROLLER, null);
return transformers.transformResource(ctx, root);
}
protected ModelNode transform(final ModelNode operation, int major, int minor) throws OperationFailedException {
return transform(PathAddress.pathAddress(operation.require(ModelDescriptionConstants.OP_ADDR)), operation, major, minor);
}
protected ModelNode transform(final PathAddress address, final ModelNode operation, int major, int minor) throws OperationFailedException {
final String operationName = operation.require(ModelDescriptionConstants.OP).asString();
final OperationTransformerRegistry transformerRegistry = registry.create(ModelVersion.create(major, minor), Collections.<PathAddress, ModelVersion>emptyMap());
final OperationTransformerRegistry.OperationTransformerEntry entry = transformerRegistry.resolveOperationTransformer(address, operationName, null);
if (entry.getTransformer() == OperationTransformer.DISCARD) {
return null;
} else {
final OperationTransformer transformer = entry.getTransformer();
return transformer.transformOperation(TRANSFORMATION_CONTEXT, address, operation).getTransformedOperation();
}
}
private ModelNode readModelRecursively(Resource resource) {
ModelNode model = new ModelNode();
model.set(resource.getModel().clone());
for (String type : resource.getChildTypes()) {
for (ResourceEntry entry : resource.getChildren(type)) {
model.get(type, entry.getName()).set(readModelRecursively(entry));
}
}
return model;
}
TransformationContext TRANSFORMATION_CONTEXT = new TransformationContext() {
@Override
public TransformationTarget getTarget() {
return null;
}
@Override
public ProcessType getProcessType() {
return ProcessType.DOMAIN_SERVER;
}
@Override
public RunningMode getRunningMode() {
return RunningMode.NORMAL;
}
@Override
public ImmutableManagementResourceRegistration getResourceRegistration(final PathAddress address) {
return resourceRegistration.getSubModel(address);
}
@Override
public ImmutableManagementResourceRegistration getResourceRegistrationFromRoot(PathAddress address) {
return resourceRegistration.getSubModel(address);
}
@Override
public Resource readResource(final PathAddress address) {
return Resource.Tools.navigate(resourceRoot, address);
}
@Override
public Resource readResourceFromRoot(final PathAddress address) {
return Resource.Tools.navigate(resourceRoot, address);
}
@Override
public TransformersLogger getLogger() {
return TransformersLogger.getLogger(getTarget());
}
@Override
public <T> T getAttachment(OperationContext.AttachmentKey<T> key) {
return null;
}
@Override
public <T> T attach(OperationContext.AttachmentKey<T> key, T value) {
return null;
}
@Override
public <T> T attachIfAbsent(OperationContext.AttachmentKey<T> key, T value) {
return null;
}
@Override
public <T> T detach(OperationContext.AttachmentKey<T> key) {
return null;
}
};
private static final ResourceDefinition ROOT = new SimpleResourceDefinition(PathElement.pathElement("test"), new NonResolvingResourceDescriptionResolver());
private static final ExpressionResolver resolver = new ExpressionResolver() {
@Override
public ModelNode resolveExpressions(ModelNode node) throws OperationFailedException {
return node;
}
};
private static class MockTransformationContext implements TransformationContext {
@Override
public TransformationTarget getTarget() {
return null;
}
@Override
public ProcessType getProcessType() {
return null;
}
@Override
public RunningMode getRunningMode() {
return null;
}
@Override
public ImmutableManagementResourceRegistration getResourceRegistration(PathAddress address) {
return null;
}
@Override
public ImmutableManagementResourceRegistration getResourceRegistrationFromRoot(PathAddress address) {
return null;
}
@Override
public Resource readResource(PathAddress address) {
return null;
}
@Override
public Resource readResourceFromRoot(PathAddress address) {
return null;
}
@Override
public TransformersLogger getLogger() {
return null;
}
@Override
public <T> T getAttachment(OperationContext.AttachmentKey<T> key) {
return null;
}
@Override
public <T> T attach(OperationContext.AttachmentKey<T> key, T value) {
return null;
}
@Override
public <T> T attachIfAbsent(OperationContext.AttachmentKey<T> key, T value) {
return null;
}
@Override
public <T> T detach(OperationContext.AttachmentKey<T> key) {
return null;
}
}
}