/* * 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.Nullable; 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.*; 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 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 <C> ModelRegistry registerInstance(ModelRegistry modelRegistry, String path, final C c) { return modelRegistry.register(unmanaged(registration(ModelPath.path(path)), c)); } public static <C> ModelRegistry registerInstance(ModelRegistry modelRegistry, String path, final C c, Action<? super C> action) { return modelRegistry.register(unmanaged(registration(ModelPath.path(path)), c, action)); } public static <C> ModelRegistry registerWithInitializer(ModelRegistry modelRegistry, String path, Class<C> type, NodeInitializerRegistry nodeInitializerRegistry) { NodeInitializerContext<C> 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<? extends ModelRegistration, ? super ModelRegistrations.Builder> definition) { return register(modelRegistry, ModelPath.path(path), definition); } public static ModelRegistry register(ModelRegistry modelRegistry, ModelPath path, Transformer<? extends ModelRegistration, ? super ModelRegistrations.Builder> definition) { return modelRegistry.register(definition.transform(registration(path))); } public static <I> ModelRegistry registerModelMap(ModelRegistry modelRegistry, String path, final Class<I> itemType, final Action<? super PolymorphicNamedEntityInstantiator<I>> registrations) { configure(modelRegistry, Initialize, ModelReference.of(path, ModelRegistryHelper.instantiatorType(itemType)), new Action<RuleAwarePolymorphicNamedEntityInstantiator<I>>() { @Override public void execute(final RuleAwarePolymorphicNamedEntityInstantiator<I> instantiator) { registrations.execute(new PolymorphicNamedEntityInstantiator<I>() { @Override public Set<? extends Class<? extends I>> getCreatableTypes() { return instantiator.getCreatableTypes(); } @Override public <U extends I> void registerFactory(Class<U> type, NamedDomainObjectFactory<? extends U> factory) { instantiator.registerFactory(type, factory, new SimpleModelRuleDescriptor("ModelRegistryHelper.modelMap")); } @Override public <S extends I> S create(String name, Class<S> type) { return instantiator.create(name, type); } }); } }); return register(modelRegistry, path, new Transformer<ModelRegistration, ModelRegistrations.Builder>() { @Override public ModelRegistration transform(ModelRegistrations.Builder modelRegistrationBuilder) { return modelMap(modelRegistrationBuilder, itemType); } }); } public static <I> ModelRegistry mutateModelMap(ModelRegistry modelRegistry, final String path, final Class<I> itemType, final Action<? super ModelMap<I>> action) { return mutate(modelRegistry, new Transformer<ModelAction, ModelActionBuilder<Object>>() { @Override public ModelAction transform(ModelActionBuilder<Object> 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<? extends ModelAction, ? super ModelActionBuilder<Object>> definition) { return modelRegistry.configure(role, definition.transform(ModelActionBuilder.of())); } public static ModelRegistry mutate(ModelRegistry modelRegistry, Transformer<? extends ModelAction, ? super ModelActionBuilder<Object>> definition) { return configure(modelRegistry, Mutate, definition); } public static <T> ModelRegistry mutate(ModelRegistry modelRegistry, Class<T> type, Action<? super T> action) { return applyInternal(modelRegistry, Mutate, type, action); } public static <T> ModelRegistry mutate(ModelRegistry modelRegistry, ModelType<T> type, Action<? super T> action) { return applyInternal(modelRegistry, Mutate, type, action); } public static <T> ModelRegistry mutate(ModelRegistry modelRegistry, ModelReference<T> reference, Action<? super T> action) { return configure(modelRegistry, Mutate, reference, action); } private static <T> ModelRegistry applyInternal(ModelRegistry modelRegistry, ModelActionRole role, final Class<T> type, final Action<? super T> action) { return applyInternal(modelRegistry, role, ModelType.of(type), action); } private static <T> ModelRegistry applyInternal(ModelRegistry modelRegistry, ModelActionRole role, final ModelType<T> type, final Action<? super T> action) { return configure(modelRegistry, role, ModelReference.of(type), action); } public static ModelRegistry mutate(ModelRegistry modelRegistry, final String path, final Action<? super MutableModelNode> action) { return configure(modelRegistry, Mutate, new Transformer<ModelAction, ModelActionBuilder<Object>>() { @Override public ModelAction transform(ModelActionBuilder<Object> objectModelActionBuilder) { return objectModelActionBuilder.path(path).node(action); } }); } public static ModelRegistry apply(ModelRegistry modelRegistry, String path, final Class<? extends RuleSource> rules) { return mutate(modelRegistry, path, new Action<MutableModelNode>() { @Override public void execute(MutableModelNode mutableModelNode) { mutableModelNode.applyToSelf(rules); } }); } public static <T> ModelRegistry configure(ModelRegistry modelRegistry, ModelActionRole role, final ModelReference<T> reference, final Action<? super T> action) { return configure(modelRegistry, role, new Transformer<ModelAction, ModelActionBuilder<Object>>() { @Override public ModelAction transform(ModelActionBuilder<Object> objectModelActionBuilder) { return objectModelActionBuilder.path(reference.getPath()).type(reference.getType()).action(action); } }); } public static <T> T get(ModelRegistry modelRegistry, String path, Class<T> 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> T realize(ModelRegistry modelRegistry, String path, Class<T> type) { return modelRegistry.realize(ModelPath.nonNullValidatedPath(path), ModelType.of(type)); } // ModelRegistrations.Builder methods public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class<C> modelType, String inputPath, Transformer<? extends C, Object> action) { return unmanaged(builder, modelType, inputPath, inputPath, action); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class<C> modelType, String inputPath, String referenceDescription, Transformer<? extends C, Object> action) { return unmanaged(builder, ModelType.of(modelType), inputPath, referenceDescription, action); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, ModelType<C> modelType, String inputPath, Transformer<? extends C, Object> action) { return unmanaged(builder, modelType, inputPath, inputPath, action); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType<C> modelType, String inputPath, String inputDescriptor, final Transformer<? extends C, Object> action) { return builder.action( ModelActionRole.Create, ModelReference.of(inputPath, ModelType.UNTYPED, inputDescriptor), new BiAction<MutableModelNode, Object>() { @Override public void execute(MutableModelNode mutableModelNode, Object input) { mutableModelNode.setPrivateData(modelType, action.transform(input)); } } ) .withProjection(new UnmanagedModelProjection<C>(modelType)) .build(); } public static <C, I> ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class<C> type, Class<I> inputType, Transformer<? extends C, ? super I> action) { return unmanaged(builder, ModelType.of(type), ModelType.of(inputType), action); } public static <C, I> ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType<C> modelType, ModelType<I> inputModelType, final Transformer<? extends C, ? super I> action) { return builder.action( ModelActionRole.Create, ModelReference.of(inputModelType), new BiAction<MutableModelNode, I>() { @Override public void execute(MutableModelNode mutableModelNode, I input) { mutableModelNode.setPrivateData(modelType, action.transform(input)); } }) .withProjection(new UnmanagedModelProjection<C>(modelType)) .build(); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class<C> type, Factory<? extends C> initializer) { return unmanaged(builder, ModelType.of(type), initializer); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, Class<C> type, C c) { return unmanaged(builder, ModelType.of(type), Factories.constant(c)); } private static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, final ModelType<C> modelType, final Factory<? extends C> initializer) { return builder.action(ModelActionRole.Create, new Action<MutableModelNode>() { @Override public void execute(MutableModelNode mutableModelNode) { mutableModelNode.setPrivateData(modelType, initializer.create()); } }) .withProjection(UnmanagedModelProjection.of(modelType)) .build(); } public static <C> ModelRegistration unmanagedNode(ModelRegistrations.Builder builder, Class<C> modelType, Action<? super MutableModelNode> action) { return unmanagedNode(builder, ModelType.of(modelType), action); } public static <C> ModelRegistration unmanagedNode(ModelRegistrations.Builder builder, ModelType<C> modelType, Action<? super MutableModelNode> action) { return builder.action(ModelActionRole.Create, action) .withProjection(new UnmanagedModelProjection<C>(modelType)) .build(); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, C c) { return unmanaged(builder, c, Actions.doNothing()); } public static <C> ModelRegistration unmanaged(ModelRegistrations.Builder builder, final C c, final Action<? super C> action) { return unmanaged(builder, ModelType.typeOf(c).getConcreteClass(), new Factory<C>() { @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 <I> ModelRegistration modelMap(ModelRegistrations.Builder builder, final Class<I> itemType) { final ModelType<RuleAwarePolymorphicNamedEntityInstantiator<I>> instantiatorType = ModelRegistryHelper.instantiatorType(itemType); ModelType<I> modelType = ModelType.of(itemType); return builder.action(ModelActionRole.Create, new Action<MutableModelNode>() { @Override public void execute(MutableModelNode mutableModelNode) { RuleAwarePolymorphicNamedEntityInstantiator<I> instantiator = new DefaultRuleAwarePolymorphicNamedEntityInstantiator<I>( new DefaultPolymorphicNamedEntityInstantiator<I>(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<ModelAction, ModelActionBuilder<?>> action) { node.applyToSelf(role, action.transform(ModelActionBuilder.of())); } public static void applyToLink(MutableModelNode node, ModelActionRole role, Transformer<ModelAction, ModelActionBuilder<?>> action) { node.applyToLink(role, action.transform(ModelActionBuilder.of())); } public static void applyTo(MutableModelNode node, NodePredicate predicate, ModelActionRole role, Transformer<? extends ModelAction, ? super ModelActionBuilder<?>> definition) { node.applyTo(predicate, role, definition.transform(ModelActionBuilder.of())); } public static void addLink(MutableModelNode node, String path, Transformer<ModelRegistration, ModelRegistrations.Builder> definition) { addLink(node, ModelPath.path(path), definition); } public static void addLink(MutableModelNode node, ModelPath path, Transformer<ModelRegistration, ModelRegistrations.Builder> 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("<test>")); } 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)); } }