/*
* 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));
}
}