/* * 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.core; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSortedSet; import com.google.common.collect.Lists; import com.google.common.util.concurrent.UncheckedExecutionException; import org.gradle.internal.UncheckedException; import org.gradle.model.internal.manage.binding.StructBindingsStore; import org.gradle.model.internal.manage.schema.ModelSchema; import org.gradle.model.internal.manage.schema.ModelSchemaStore; import org.gradle.model.internal.manage.schema.extract.*; import org.gradle.model.internal.type.ModelType; import org.gradle.model.internal.type.ModelTypes; import java.util.List; import java.util.concurrent.ExecutionException; public class DefaultNodeInitializerRegistry implements NodeInitializerRegistry { public static final ModelReference<NodeInitializerRegistry> DEFAULT_REFERENCE = ModelReference.of("nodeInitializerRegistry", NodeInitializerRegistry.class); private final LoadingCache<NodeInitializerContext<?>, NodeInitializer> cache = CacheBuilder.newBuilder() .weakValues() .build(new CacheLoader<NodeInitializerContext<?>, NodeInitializer>() { @Override public NodeInitializer load(NodeInitializerContext<?> context) throws Exception { return extractNodeInitializer(context); } }); private final List<NodeInitializerExtractionStrategy> allStrategies; private final List<NodeInitializerExtractionStrategy> additionalStrategies; private final ModelSchemaStore schemaStore; public DefaultNodeInitializerRegistry(ModelSchemaStore schemaStore, StructBindingsStore structBindingsStore) { this.schemaStore = schemaStore; this.allStrategies = Lists.newArrayList( new ModelSetNodeInitializerExtractionStrategy(), new SpecializedMapNodeInitializerExtractionStrategy(), new ModelMapNodeInitializerExtractionStrategy(), new ScalarCollectionNodeInitializerExtractionStrategy(), new ManagedImplStructNodeInitializerExtractionStrategy(structBindingsStore) ); additionalStrategies = Lists.newArrayList(); } private ModelTypeInitializationException canNotConstructTypeException(NodeInitializerContext<?> context) { ImmutableSortedSet.Builder<ModelType<?>> constructibleTypes = ImmutableSortedSet.orderedBy(ModelTypes.displayOrder()); for (NodeInitializerExtractionStrategy extractor : additionalStrategies) { for (ModelType<?> constructibleType : extractor.supportedTypes()) { if (context.getConstraints().isSatisfiedBy(constructibleType)) { constructibleTypes.add(constructibleType); } } } return new ModelTypeInitializationException(context, schemaStore, ScalarTypes.TYPES, constructibleTypes.build()); } @Override public NodeInitializer getNodeInitializer(NodeInitializerContext<?> nodeInitializerContext) { try { return cache.get(nodeInitializerContext); } catch (ExecutionException e) { throw UncheckedException.throwAsUncheckedException(e); } catch (UncheckedExecutionException e) { throw UncheckedException.throwAsUncheckedException(e.getCause()); } } private <T> NodeInitializer extractNodeInitializer(NodeInitializerContext<T> context) { ModelSchema<T> schema = schemaStore.getSchema(context.getModelType()); for (NodeInitializerExtractionStrategy extractor : allStrategies) { NodeInitializer nodeInitializer = extractor.extractNodeInitializer(schema, context); if (nodeInitializer != null) { return nodeInitializer; } } throw canNotConstructTypeException(context); } @Override public void ensureHasInitializer(NodeInitializerContext<?> nodeInitializer) { getNodeInitializer(nodeInitializer); } @Override public void registerStrategy(NodeInitializerExtractionStrategy strategy) { allStrategies.add(0, strategy); additionalStrategies.add(0, strategy); } }