software.amazon.smithy.model.Model Maven / Gradle / Ivy
/*
* Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file 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 software.amazon.smithy.model;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.function.Function;
import java.util.stream.Stream;
import software.amazon.smithy.model.knowledge.KnowledgeIndex;
import software.amazon.smithy.model.loader.ModelAssembler;
import software.amazon.smithy.model.node.ExpectationNotMetException;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.shapes.BigDecimalShape;
import software.amazon.smithy.model.shapes.BigIntegerShape;
import software.amazon.smithy.model.shapes.BlobShape;
import software.amazon.smithy.model.shapes.BooleanShape;
import software.amazon.smithy.model.shapes.ByteShape;
import software.amazon.smithy.model.shapes.DocumentShape;
import software.amazon.smithy.model.shapes.DoubleShape;
import software.amazon.smithy.model.shapes.EnumShape;
import software.amazon.smithy.model.shapes.FloatShape;
import software.amazon.smithy.model.shapes.IntEnumShape;
import software.amazon.smithy.model.shapes.IntegerShape;
import software.amazon.smithy.model.shapes.ListShape;
import software.amazon.smithy.model.shapes.LongShape;
import software.amazon.smithy.model.shapes.MapShape;
import software.amazon.smithy.model.shapes.MemberShape;
import software.amazon.smithy.model.shapes.NumberShape;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ResourceShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.SetShape;
import software.amazon.smithy.model.shapes.Shape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.model.shapes.ShortShape;
import software.amazon.smithy.model.shapes.StringShape;
import software.amazon.smithy.model.shapes.StructureShape;
import software.amazon.smithy.model.shapes.TimestampShape;
import software.amazon.smithy.model.shapes.ToShapeId;
import software.amazon.smithy.model.shapes.UnionShape;
import software.amazon.smithy.model.traits.Trait;
import software.amazon.smithy.model.traits.TraitDefinition;
import software.amazon.smithy.model.traits.TraitFactory;
import software.amazon.smithy.model.validation.ValidatorFactory;
import software.amazon.smithy.utils.BuilderRef;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.ToSmithyBuilder;
/**
* A Smithy model that contains shapes, traits, metadata, and various
* computed information used to interpret the model.
*/
public final class Model implements ToSmithyBuilder {
/** Specifies the highest supported version of the IDL. */
public static final String MODEL_VERSION = "2.0";
/** The map of metadata keys to their "node" values. */
private final Map metadata;
/** A map of shape ID to shapes that backs the shape map. */
private final Map shapeMap;
/** A cache of shapes of a specific type. */
private final Map, Set extends Shape>> cachedTypes = new ConcurrentHashMap<>();
/** Cache of computed {@link KnowledgeIndex} instances. */
private final Map blackboard = new ConcurrentSkipListMap<>();
/** Lazily computed trait mappings. */
private volatile TraitCache traitCache;
/** Lazily computed hashcode. */
private int hash;
private Model(Builder builder) {
shapeMap = builder.shapeMap.copy();
metadata = builder.metadata.copy();
}
/**
* Builds an explicitly configured Smithy model.
*
* Note that the builder does not validate the correctness of the
* model. Use the {@link #assembler()} method to build and
* validate a model.
*
* @return Returns a model builder.
* @see #assembler()
*/
public static Builder builder() {
return new Builder();
}
/**
* Assembles and validates a Smithy model from files, nodes, and other
* disparate sources.
*
* @return Returns a model assembler.
*/
public static ModelAssembler assembler() {
return new ModelAssembler();
}
/**
* Creates a {@link ModelAssembler} that is configured to discover traits,
* validators, and built-in validators using the given
* {@code ClassLoader}.
*
* @param classLoader Class loader used to discover services.
* @return Returns a model assembler.
*/
public static ModelAssembler assembler(ClassLoader classLoader) {
return new ModelAssembler()
.traitFactory(TraitFactory.createServiceFactory(classLoader))
.validatorFactory(ValidatorFactory.createServiceFactory(classLoader));
}
/**
* Gets a metadata property by namespace and name.
*
* @param name Name of the property to retrieve.
* @return Returns the optional property.
*/
public Optional getMetadataProperty(String name) {
return Optional.ofNullable(metadata.get(name));
}
/**
* @return Gets the unmodifiable metadata of the model across all
* namespaces.
*/
public Map getMetadata() {
return metadata;
}
/**
* Gets the trait definition of a specific trait shape ID.
*
* @param traitId ID of the shape to get the trait definition of.
* @return Returns the optionally found trait definition.
*/
public Optional getTraitDefinition(ToShapeId traitId) {
return getShape(traitId.toShapeId()).flatMap(shape -> shape.getTrait(TraitDefinition.class));
}
/**
* Gets a set of shapes in the model marked with a specific trait.
*
* @param trait Trait shape ID to look for on shapes.
* @return Returns the immutable set of matching shapes.
*/
public Set getShapesWithTrait(ToShapeId trait) {
Map> mappings = getTraitCache().traitIdsToShapes;
return Collections.unmodifiableSet(mappings.getOrDefault(trait.toShapeId(), Collections.emptySet()));
}
private TraitCache getTraitCache() {
TraitCache cache = traitCache;
if (cache == null) {
synchronized (this) {
cache = traitCache;
if (cache == null) {
traitCache = cache = new TraitCache(this.shapeMap.values());
}
}
}
return cache;
}
/**
* Gets the immutable set of {@code ShapeId} in the model.
*
* @return Returns the shape IDs.
*/
public Set getShapeIds() {
return shapeMap.keySet();
}
/**
* Gets a set of shapes in the model marked with a specific trait.
*
* The result is an exact match on trait classes and does not utilize
* any kind of polymorphic instance of checks.
*
* @param trait Trait class to look for on shapes.
* @return Returns the immutable set of matching shapes.
*/
public Set getShapesWithTrait(Class extends Trait> trait) {
Map, Set> mappings = getTraitCache().traitsToShapes;
return Collections.unmodifiableSet(mappings.getOrDefault(trait, Collections.emptySet()));
}
/**
* Gets an immutable set of all bigDecimals in the Model.
*
* @return Returns the Set of {@code bigDecimals}s.
*/
public Set getBigDecimalShapes() {
return toSet(BigDecimalShape.class);
}
/**
* Gets an immutable set of all bigDecimals in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code bigdecimal}s that have a specific trait.
*/
public Set getBigDecimalShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BigDecimalShape.class);
}
/**
* Gets an immutable set of all bigIntegers in the Model.
*
* @return Returns the Set of {@code bigIntegers}s.
*/
public Set getBigIntegerShapes() {
return toSet(BigIntegerShape.class);
}
/**
* Gets an immutable set of all bigIntegers in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code bigIntegers}s that have a specific trait.
*/
public Set getBigIntegerShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BigIntegerShape.class);
}
/**
* Gets an immutable set of all blobs in the Model.
*
* @return Returns the Set of {@code blob}s.
*/
public Set getBlobShapes() {
return toSet(BlobShape.class);
}
/**
* Gets an immutable set of all blobs in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code blob}s that have a specific trait.
*/
public Set getBlobShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BlobShape.class);
}
/**
* Gets an immutable set of all booleans in the Model.
*
* @return Returns the Set of {@code boolean}s.
*/
public Set getBooleanShapes() {
return toSet(BooleanShape.class);
}
/**
* Gets an immutable set of all booleans in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code boolean}s that have a specific trait.
*/
public Set getBooleanShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), BooleanShape.class);
}
/**
* Gets an immutable set of all bytes in the Model.
*
* @return Returns the Set of {@code byte}s.
*/
public Set getByteShapes() {
return toSet(ByteShape.class);
}
/**
* Gets an immutable set of all bytes in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code byte}s that have a specific trait.
*/
public Set getByteShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ByteShape.class);
}
/**
* Gets an immutable set of all documents in the Model.
*
* @return Returns the Set of {@code document}s.
*/
public Set getDocumentShapes() {
return toSet(DocumentShape.class);
}
/**
* Gets an immutable set of all documents in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code document}s that have a specific trait.
*/
public Set getDocumentShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), DocumentShape.class);
}
/**
* Gets an immutable set of all doubles in the Model.
*
* @return Returns the Set of {@code double}s.
*/
public Set getDoubleShapes() {
return toSet(DoubleShape.class);
}
/**
* Gets an immutable set of all doubles in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code double}s that have a specific trait.
*/
public Set getDoubleShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), DoubleShape.class);
}
/**
* Gets an immutable set of all floats in the Model.
*
* @return Returns the Set of {@code float}s.
*/
public Set getFloatShapes() {
return toSet(FloatShape.class);
}
/**
* Gets an immutable set of all floats in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code float}s that have a specific trait.
*/
public Set getFloatShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), FloatShape.class);
}
/**
* Gets an immutable set of all integers in the Model.
*
* @return Returns the Set of {@code integer}s.
*/
public Set getIntegerShapes() {
return toSet(IntegerShape.class);
}
/**
* Gets an immutable set of all integers in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code integer}s that have a specific trait.
*/
public Set getIntegerShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), IntegerShape.class);
}
/**
* Gets an immutable set of all intEnums in the Model.
*
* @return Returns the Set of {@code intEnum}s.
*/
public Set getIntEnumShapes() {
return toSet(IntEnumShape.class);
}
/**
* Gets an immutable set of all intEnums in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code intEnum}s that have a specific trait.
*/
public Set getIntEnumShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), IntEnumShape.class);
}
/**
* Gets an immutable set of all lists in the Model.
*
* @return Returns the Set of {@code list}s.
*/
public Set getListShapes() {
return toSet(ListShape.class);
}
/**
* Gets an immutable set of all lists in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code list}s that have a specific trait.
*/
public Set getListShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ListShape.class);
}
/**
* Gets an immutable set of all longs in the Model.
*
* @return Returns the Set of {@code long}s.
*/
public Set getLongShapes() {
return toSet(LongShape.class);
}
/**
* Gets an immutable set of all longs in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code long}s that have a specific trait.
*/
public Set getLongShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), LongShape.class);
}
/**
* Gets an immutable set of all maps in the Model.
*
* @return Returns the Set of {@code map}s.
*/
public Set getMapShapes() {
return toSet(MapShape.class);
}
/**
* Gets an immutable set of all maps in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code map}s that have a specific trait.
*/
public Set getMapShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), MapShape.class);
}
/**
* Gets an immutable set of all members in the Model.
*
* @return Returns the Set of {@code member}s.
*/
public Set getMemberShapes() {
return toSet(MemberShape.class);
}
/**
* Gets an immutable set of all members in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code member}s that have a specific trait.
*/
public Set getMemberShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), MemberShape.class);
}
/**
* Gets an immutable set of all operations in the Model.
*
* @return Returns the Set of {@code operation}s.
*/
public Set getOperationShapes() {
return toSet(OperationShape.class);
}
/**
* Gets an immutable set of all operations in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code operation}s that have a specific trait.
*/
public Set getOperationShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), OperationShape.class);
}
/**
* Gets an immutable set of all resources in the Model.
*
* @return Returns the Set of {@code resource}s.
*/
public Set getResourceShapes() {
return toSet(ResourceShape.class);
}
/**
* Gets an immutable set of all resources in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code resource}s that have a specific trait.
*/
public Set getResourceShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ResourceShape.class);
}
/**
* Gets an immutable set of all services in the Model.
*
* @return Returns the Set of {@code service}s.
*/
public Set getServiceShapes() {
return toSet(ServiceShape.class);
}
/**
* Gets an immutable set of all services in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code service}s that have a specific trait.
*/
public Set getServiceShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ServiceShape.class);
}
/**
* Gets an immutable set of all sets in the Model.
*
* @return Returns the Set of {@code set}s.
*/
@Deprecated
public Set getSetShapes() {
return toSet(SetShape.class);
}
/**
* Gets an immutable set of all sets in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code set}s that have a specific trait.
*/
@Deprecated
public Set getSetShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), SetShape.class);
}
/**
* Gets an immutable set of all shorts in the Model.
*
* @return Returns the Set of {@code short}s.
*/
public Set getShortShapes() {
return toSet(ShortShape.class);
}
/**
* Gets an immutable set of all shorts in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code short}s that have a specific trait.
*/
public Set getShortShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), ShortShape.class);
}
/**
* Gets an immutable set of all strings in the Model.
*
* @return Returns the Set of {@code string}s.
*/
public Set getStringShapes() {
return toSet(StringShape.class);
}
/**
* Gets an immutable set of all strings in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code string}s that have a specific trait.
*/
public Set getStringShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), StringShape.class);
}
/**
* Gets an immutable set of all enums in the Model.
*
* @return Returns the Set of {@code enum}s.
*/
public Set getEnumShapes() {
return toSet(EnumShape.class);
}
/**
* Gets an immutable set of all enums in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code enum}s that have a specific trait.
*/
public Set getEnumShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), EnumShape.class);
}
/**
* Gets an immutable set of all structures in the Model.
*
* @return Returns the Set of {@code structure}s.
*/
public Set getStructureShapes() {
return toSet(StructureShape.class);
}
/**
* Gets an immutable set of all structures in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code structure}s that have a specific trait.
*/
public Set getStructureShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), StructureShape.class);
}
/**
* Gets an immutable set of all timestamps in the Model.
*
* @return Returns the Set of {@code timestamp}s.
*/
public Set getTimestampShapes() {
return toSet(TimestampShape.class);
}
/**
* Gets an immutable set of all timestamps in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code timestamp}s that have a specific trait.
*/
public Set getTimestampShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), TimestampShape.class);
}
/**
* Gets an immutable set of all unions in the Model.
*
* @return Returns the Set of {@code union}s.
*/
public Set getUnionShapes() {
return toSet(UnionShape.class);
}
/**
* Gets an immutable set of all unions in the Model that have a specific trait.
*
* @param trait The exact trait class to look for on shapes.
* @return Returns the set of {@code union}s that have a specific trait.
*/
public Set getUnionShapesWithTrait(Class extends Trait> trait) {
return new ShapeTypeFilteredSet<>(getShapesWithTrait(trait), UnionShape.class);
}
/**
* Gets a set of every trait shape ID that is used in the model.
*
* @return Returns the shape IDs of traits used in the model.
*/
public Set getAppliedTraits() {
return Collections.unmodifiableSet(getTraitCache().traitIdsToShapes.keySet());
}
/**
* Returns true if the given trait shape ID was used in the model.
*
* @param trait The trait class to check.
* @return Returns true if the trait was used in the model.
*/
public boolean isTraitApplied(Class extends Trait> trait) {
return !getShapesWithTrait(trait).isEmpty();
}
/**
* Attempts to retrieve a {@link Shape} by {@link ShapeId}.
*
* @param id Shape to retrieve by ID.
* @return Returns the optional shape.
*/
public Optional getShape(ShapeId id) {
return Optional.ofNullable(shapeMap.get(id));
}
/**
* Attempts to retrieve a {@link Shape} by {@link ShapeId} and
* throws if not found.
*
* @param id Shape to retrieve by ID.
* @return Returns the shape.
* @throws ExpectationNotMetException if the shape is not found.
*/
public Shape expectShape(ShapeId id) {
return getShape(id).orElseThrow(() -> new ExpectationNotMetException(
"Shape not found in model: " + id, SourceLocation.NONE));
}
/**
* Attempts to retrieve a {@link Shape} by {@link ShapeId} and
* throws if not found or if the shape is not of the expected type.
*
* @param id Shape to retrieve by ID.
* @param type Shape type to expect and convert to.
* @param Expected shape type.
* @return Returns the shape.
* @throws ExpectationNotMetException if the shape is not found or is not the expected type.
*/
@SuppressWarnings("unchecked")
public T expectShape(ShapeId id, Class type) {
Shape shape = expectShape(id);
if (type.isInstance(shape)) {
return (T) shape;
}
throw new ExpectationNotMetException(String.format(
"Expected shape `%s` to be an instance of `%s`, but found `%s`",
id, type.getSimpleName(), shape.getType()), shape);
}
/**
* Gets a stream of {@link Shape}s in the index.
*
* @return Returns a stream of shapes.
*/
public Stream shapes() {
return shapeMap.values().stream();
}
/**
* Gets a stream of shapes in the index of a specific type {@code T}.
*
* The provided shapeType class must exactly match the class of a
* shape in the model in order to be returned from this method;
* that is, the provided class must be a concrete subclass of
* {@link Shape} and not an abstract class like {@link NumberShape}.
*
* @param shapeType Shape type {@code T} to retrieve.
* @param Shape type to stream from the index.
* @return A stream of shapes of {@code T} matching {@code shapeType}.
*/
public Stream shapes(Class shapeType) {
return toSet(shapeType).stream();
}
/**
* Gets an immutable Set of shapes of a specific type.
*
* @param shapeType Type of shape to get a set of.
* @param Shape type to get from the index.
* @return Returns an unmodifiable set of shapes.
*/
@SuppressWarnings("unchecked")
public Set toSet(Class shapeType) {
return (Set) cachedTypes.computeIfAbsent(shapeType, t -> {
Set result = new HashSet<>();
for (Shape shape : shapeMap.values()) {
if (shapeType.isInstance(shape)) {
result.add((T) shape);
}
}
return Collections.unmodifiableSet(result);
});
}
/**
* Converts the model to an immutable Set of shapes.
*
* @return Returns an unmodifiable set of shapes.
*/
public Set toSet() {
return new AbstractSet() {
@Override
public int size() {
return shapeMap.size();
}
@Override
public boolean contains(Object o) {
return o instanceof Shape && shapeMap.containsKey(((Shape) o).getId());
}
@Override
public Iterator iterator() {
return shapeMap.values().iterator();
}
@Override
public Stream stream() {
return shapes();
}
@Override
public Stream parallelStream() {
return shapes().parallel();
}
};
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Model)) {
return false;
} else if (other == this) {
return true;
}
Model otherModel = (Model) other;
return getMetadata().equals(otherModel.getMetadata()) && shapeMap.equals(otherModel.shapeMap);
}
@Override
public int hashCode() {
int result = hash;
if (result == 0) {
result = Objects.hash(getMetadata(), shapeMap.keySet());
hash = result;
}
return result;
}
@Override
public Builder toBuilder() {
return builder()
.metadata(getMetadata())
.addShapes(this);
}
/**
* This method is deprecated. Use the {@code of} method of the
* {@link KnowledgeIndex} you wish to create instead.
*
* @param type Type of knowledge index to retrieve.
* @param The type of knowledge index to retrieve.
* @return Returns the computed knowledge index.
*/
@Deprecated
public T getKnowledge(Class type) {
return getKnowledge(type, m -> {
try {
return type.getConstructor(Model.class).newInstance(this);
} catch (NoSuchMethodException e) {
String message = String.format(
"KnowledgeIndex for type `%s` does not expose a public constructor that accepts a Model", type);
throw new RuntimeException(message, e);
} catch (ReflectiveOperationException e) {
String message = String.format(
"Unable to create a KnowledgeIndex for type `%s`: %s", type, e.getMessage());
throw new RuntimeException(message, e);
}
});
}
/**
* Gets a computed "knowledge index" of a specific type for the model
* and caches it for subsequent retrieval.
*
* This method should not typically be called directly because
* KnowledgeIndex classes should all provide a public static {@code of}
* method that accepts a {@code Model} and returns an instance of the
* index by invoking {@code getKnowledge}.
*
*
If a {@link KnowledgeIndex} of the given type has not yet been
* computed, one will be created using the provided {@code constructor}
* function that accepts a {@link Model}. Computed knowledge indexes are
* cached and returned on subsequent retrievals.
*
* @param type Type of knowledge index to retrieve.
* @param constructor The method used to create {@code type}.
* @param The type of knowledge index to retrieve.
* @return Returns the computed knowledge index.
*/
@SuppressWarnings("unchecked")
public T getKnowledge(Class type, Function constructor) {
return (T) blackboard.computeIfAbsent(type.getName(), t -> constructor.apply(this));
}
/**
* Builder used to create a Model.
*/
public static final class Builder implements SmithyBuilder {
private final BuilderRef