All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.gradle.model.internal.fixture.ModelRegistryHelperExtension Maven / Gradle / Ivy

There is a newer version: 8.11.1
Show newest version
/*
 * Copyright 2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.gradle.model.internal.fixture;

import org.gradle.api.Action;
import org.gradle.api.NamedDomainObjectFactory;
import org.gradle.api.Transformer;
import org.gradle.api.internal.DefaultPolymorphicNamedEntityInstantiator;
import org.gradle.api.internal.PolymorphicNamedEntityInstantiator;
import org.gradle.api.internal.rules.DefaultRuleAwarePolymorphicNamedEntityInstantiator;
import org.gradle.api.internal.rules.RuleAwarePolymorphicNamedEntityInstantiator;
import org.gradle.internal.Actions;
import org.gradle.internal.BiAction;
import org.gradle.internal.Factories;
import org.gradle.internal.Factory;
import org.gradle.model.ModelMap;
import org.gradle.model.RuleSource;
import org.gradle.model.internal.core.ChildNodeInitializerStrategyAccessors;
import org.gradle.model.internal.core.ModelAction;
import org.gradle.model.internal.core.ModelActionRole;
import org.gradle.model.internal.core.ModelMapModelProjection;
import org.gradle.model.internal.core.ModelNode;
import org.gradle.model.internal.core.ModelPath;
import org.gradle.model.internal.core.ModelReference;
import org.gradle.model.internal.core.ModelRegistration;
import org.gradle.model.internal.core.ModelRegistrations;
import org.gradle.model.internal.core.MutableModelNode;
import org.gradle.model.internal.core.NodeBackedModelMap;
import org.gradle.model.internal.core.NodeInitializerContext;
import org.gradle.model.internal.core.NodeInitializerRegistry;
import org.gradle.model.internal.core.NodePredicate;
import org.gradle.model.internal.core.UnmanagedModelProjection;
import org.gradle.model.internal.core.rule.describe.SimpleModelRuleDescriptor;
import org.gradle.model.internal.registry.DefaultModelRegistry;
import org.gradle.model.internal.registry.ModelRegistry;
import org.gradle.model.internal.type.ModelType;
import org.gradle.model.internal.type.ModelTypes;

import javax.annotation.Nullable;
import java.util.Set;

import static org.gradle.model.internal.core.ModelActionRole.Initialize;
import static org.gradle.model.internal.core.ModelActionRole.Mutate;
import static org.gradle.model.internal.core.NodeInitializerContext.forType;

/**
 * A helper for adding rules to a model registry.
 *
 * Allows unsafe use of the model registry by allow registering of rules that can close over external, unmanaged, state.
 */
public class ModelRegistryHelperExtension {
    // ModelRegistry methods

    public static MutableModelNode atState(DefaultModelRegistry modelRegistry, String path, ModelNode.State state) {
        return (MutableModelNode) modelRegistry.atState(ModelPath.path(path), state);
    }

    public static MutableModelNode atStateOrLater(ModelRegistry modelRegistry, String path, ModelNode.State state) {
        return (MutableModelNode) modelRegistry.atStateOrLater(ModelPath.path(path), state);
    }

    public static ModelNode.State state(ModelRegistry modelRegistry, String path) {
        return modelRegistry.state(ModelPath.path(path));
    }

    @Nullable
    public static MutableModelNode node(DefaultModelRegistry modelRegistry, String path) {
        return modelRegistry.node(ModelPath.path(path));
    }

    public static  ModelRegistry registerInstance(ModelRegistry modelRegistry, String path, final C c) {
        return modelRegistry.register(unmanaged(registration(ModelPath.path(path)), c));
    }

    public static  ModelRegistry registerInstance(ModelRegistry modelRegistry, String path, final C c, Action action) {
        return modelRegistry.register(unmanaged(registration(ModelPath.path(path)), c, action));
    }

    public static  ModelRegistry registerWithInitializer(ModelRegistry modelRegistry, String path, Class type, NodeInitializerRegistry nodeInitializerRegistry) {
        NodeInitializerContext nodeInitializerContext = forType(ModelType.of(type));
        ModelRegistration registration = ModelRegistrations.of(ModelPath.path(path), nodeInitializerRegistry.getNodeInitializer(nodeInitializerContext)).descriptor("create " + path).build();
        modelRegistry.register(registration);
        return modelRegistry;
    }

    public static ModelRegistry register(ModelRegistry modelRegistry, String path, Transformer definition) {
        return register(modelRegistry, ModelPath.path(path), definition);
    }

    public static ModelRegistry register(ModelRegistry modelRegistry, ModelPath path, Transformer definition) {
        return modelRegistry.register(definition.transform(registration(path)));
    }

    public static  ModelRegistry registerModelMap(ModelRegistry modelRegistry, String path, final Class itemType, final Action> registrations) {
        configure(modelRegistry, Initialize, ModelReference.of(path, ModelRegistryHelper.instantiatorType(itemType)), new Action>() {
            @Override
            public void execute(final RuleAwarePolymorphicNamedEntityInstantiator instantiator) {
                registrations.execute(new PolymorphicNamedEntityInstantiator() {
                    @Override
                    public Set> getCreatableTypes() {
                        return instantiator.getCreatableTypes();
                    }

                    @Override
                    public  void registerFactory(Class type, NamedDomainObjectFactory factory) {
                        instantiator.registerFactory(type, factory, new SimpleModelRuleDescriptor("ModelRegistryHelper.modelMap"));
                    }

                    @Override
                    public  S create(String name, Class type) {
                        return instantiator.create(name, type);
                    }
                });
            }
        });
        return register(modelRegistry, path, new Transformer() {
            @Override
            public ModelRegistration transform(ModelRegistrations.Builder modelRegistrationBuilder) {
                return modelMap(modelRegistrationBuilder, itemType);
            }
        });
    }

    public static  ModelRegistry mutateModelMap(ModelRegistry modelRegistry, final String path, final Class itemType, final Action> action) {
        return mutate(modelRegistry, new Transformer>() {
            @Override
            public ModelAction transform(ModelActionBuilder builder) {
                return builder.path(path).type(ModelTypes.modelMap(itemType)).action(action);
            }
        });
    }

    private static ModelRegistrations.Builder registration(ModelPath path) {
        return ModelRegistrations.of(path).descriptor(path + " creator");
    }

    public static ModelRegistry configure(ModelRegistry modelRegistry, ModelActionRole role, Transformer> definition) {
        return modelRegistry.configure(role, definition.transform(ModelActionBuilder.of()));
    }

    public static ModelRegistry mutate(ModelRegistry modelRegistry, Transformer> definition) {
        return configure(modelRegistry, Mutate, definition);
    }

    public static  ModelRegistry mutate(ModelRegistry modelRegistry, Class type, Action action) {
        return applyInternal(modelRegistry, Mutate, type, action);
    }

    public static  ModelRegistry mutate(ModelRegistry modelRegistry, ModelType type, Action action) {
        return applyInternal(modelRegistry, Mutate, type, action);
    }

    public static  ModelRegistry mutate(ModelRegistry modelRegistry, ModelReference reference, Action action) {
        return configure(modelRegistry, Mutate, reference, action);
    }

    private static  ModelRegistry applyInternal(ModelRegistry modelRegistry, ModelActionRole role, final Class type, final Action action) {
        return applyInternal(modelRegistry, role, ModelType.of(type), action);
    }

    private static  ModelRegistry applyInternal(ModelRegistry modelRegistry, ModelActionRole role, final ModelType type, final Action action) {
        return configure(modelRegistry, role, ModelReference.of(type), action);
    }

    public static ModelRegistry mutate(ModelRegistry modelRegistry, final String path, final Action action) {
        return configure(modelRegistry, Mutate, new Transformer>() {
            @Override
            public ModelAction transform(ModelActionBuilder objectModelActionBuilder) {
                return objectModelActionBuilder.path(path).node(action);
            }
        });
    }

    public static ModelRegistry apply(ModelRegistry modelRegistry, String path, final Class rules) {
        return mutate(modelRegistry, path, new Action() {
            @Override
            public void execute(MutableModelNode mutableModelNode) {
                mutableModelNode.applyToSelf(rules);
            }
        });
    }

    public static  ModelRegistry configure(ModelRegistry modelRegistry, ModelActionRole role, final ModelReference reference, final Action action) {
        return configure(modelRegistry, role, new Transformer>() {
            @Override
            public ModelAction transform(ModelActionBuilder objectModelActionBuilder) {
                return objectModelActionBuilder.path(reference.getPath()).type(reference.getType()).action(action);
            }
        });
    }

    public static  T get(ModelRegistry modelRegistry, String path, Class type) {
        return modelRegistry.realize(ModelPath.nonNullValidatedPath(path), ModelType.of(type));
    }

    public static Object get(ModelRegistry modelRegistry, String path) {
        return get(modelRegistry, path, Object.class);
    }

    public static Object get(ModelRegistry modelRegistry, ModelPath path) {
        return get(modelRegistry, path.toString());
    }

    public static Object realize(ModelRegistry modelRegistry, String path) {
        return modelRegistry.realize(ModelPath.nonNullValidatedPath(path), ModelType.UNTYPED);
    }

    public static  T realize(ModelRegistry modelRegistry, String path, Class type) {
        return modelRegistry.realize(ModelPath.nonNullValidatedPath(path), ModelType.of(type));
    }

    // ModelRegistrations.Builder methods

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class modelType, String inputPath, Transformer action) {
        return unmanaged(builder, modelType, inputPath, inputPath, action);
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class modelType, String inputPath, String referenceDescription, Transformer action) {
        return unmanaged(builder, ModelType.of(modelType), inputPath, referenceDescription, action);
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, ModelType modelType, String inputPath, Transformer action) {
        return unmanaged(builder, modelType, inputPath, inputPath, action);
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType modelType, String inputPath, String inputDescriptor, final Transformer action) {
        return builder.action(
            ModelActionRole.Create,
            ModelReference.of(inputPath, ModelType.UNTYPED, inputDescriptor),
            new BiAction() {
                @Override
                public void execute(MutableModelNode mutableModelNode, Object input) {
                    mutableModelNode.setPrivateData(modelType, action.transform(input));
                }
            }
        )
            .withProjection(new UnmanagedModelProjection(modelType))
            .build();
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class type, Class inputType, Transformer action) {
        return unmanaged(builder, ModelType.of(type), ModelType.of(inputType), action);
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType modelType, ModelType inputModelType, final Transformer action) {
        return builder.action(
            ModelActionRole.Create,
            ModelReference.of(inputModelType),
            new BiAction() {
                @Override
                public void execute(MutableModelNode mutableModelNode, I input) {
                    mutableModelNode.setPrivateData(modelType, action.transform(input));
                }
            })
            .withProjection(new UnmanagedModelProjection(modelType))
            .build();
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class type, Factory initializer) {
        return unmanaged(builder, ModelType.of(type), initializer);
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class type, C c) {
        return unmanaged(builder, ModelType.of(type), Factories.constant(c));
    }

    private static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType modelType, final Factory initializer) {
        return builder.action(ModelActionRole.Create,
            new Action() {
                @Override
                public void execute(MutableModelNode mutableModelNode) {
                    mutableModelNode.setPrivateData(modelType, initializer.create());
                }
            })
            .withProjection(UnmanagedModelProjection.of(modelType))
            .build();
    }

    public static  ModelRegistration unmanagedNode(ModelRegistrations.Builder builder, Class modelType, Action action) {
        return unmanagedNode(builder, ModelType.of(modelType), action);
    }

    public static  ModelRegistration unmanagedNode(ModelRegistrations.Builder builder, ModelType modelType, Action action) {
        return builder.action(ModelActionRole.Create, action)
            .withProjection(new UnmanagedModelProjection(modelType))
            .build();
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, C c) {
        return unmanaged(builder, c, Actions.doNothing());
    }

    public static  ModelRegistration unmanaged(ModelRegistrations.Builder builder, final C c, final Action action) {
        return unmanaged(builder, ModelType.typeOf(c).getConcreteClass(), new Factory() {
            @Override
            public C create() {
                action.execute(c);
                return c;
            }
        });
    }

    public static ModelRegistration asUnmanaged(ModelRegistrations.Builder builder, Class type) {
        return builder.withProjection(UnmanagedModelProjection.of(type)).build();
    }

    public static  ModelRegistration modelMap(ModelRegistrations.Builder builder, final Class itemType) {
        final ModelType> instantiatorType = ModelRegistryHelper.instantiatorType(itemType);

        ModelType modelType = ModelType.of(itemType);
        return builder.action(ModelActionRole.Create,
            new Action() {
                @Override
                public void execute(MutableModelNode mutableModelNode) {
                    RuleAwarePolymorphicNamedEntityInstantiator instantiator = new DefaultRuleAwarePolymorphicNamedEntityInstantiator(
                        new DefaultPolymorphicNamedEntityInstantiator(itemType, "this collection")
                    );
                    mutableModelNode.setPrivateData(instantiatorType, instantiator);
                }
            })
            .withProjection(ModelMapModelProjection.unmanaged(
                modelType,
                ChildNodeInitializerStrategyAccessors.of(NodeBackedModelMap.createUsingParentNode(modelType)))
            )
            .withProjection(UnmanagedModelProjection.of(instantiatorType))
            .build();
    }

    // MutableModelNode methods

    public static void applyToSelf(MutableModelNode node, ModelActionRole role, Transformer> action) {
        node.applyToSelf(role, action.transform(ModelActionBuilder.of()));
    }

    public static void applyToLink(MutableModelNode node, ModelActionRole role, Transformer> action) {
        node.applyToLink(role, action.transform(ModelActionBuilder.of()));
    }

    public static void applyTo(MutableModelNode node, NodePredicate predicate, ModelActionRole role, Transformer> definition) {
        node.applyTo(predicate, role, definition.transform(ModelActionBuilder.of()));
    }

    public static void addLink(MutableModelNode node, String path, Transformer definition) {
        addLink(node, ModelPath.path(path), definition);
    }

    public static void addLink(MutableModelNode node, ModelPath path, Transformer definition) {
        node.addLink(definition.transform(registration(path)));
    }

    public static void addReference(MutableModelNode node, String name, Class type, MutableModelNode target) {
        node.addReference(name, ModelType.of(type), target, new SimpleModelRuleDescriptor(""));
    }

    public static void addLinkInstance(MutableModelNode node, String path, Object instance) {
        addLinkInstance(node, ModelPath.path(path), instance);
    }

    public static void addLinkInstance(MutableModelNode node, ModelPath path, Object instance) {
        node.addLink(unmanaged(registration(path), instance));
    }
}