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

software.amazon.smithy.build.PluginContext Maven / Gradle / Ivy

/*
 * Copyright 2019 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.build;

import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import software.amazon.smithy.build.model.ProjectionConfig;
import software.amazon.smithy.model.FromSourceLocation;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.node.Node;
import software.amazon.smithy.model.node.ObjectNode;
import software.amazon.smithy.model.shapes.ToShapeId;
import software.amazon.smithy.model.transform.ModelTransformer;
import software.amazon.smithy.model.validation.ValidationEvent;
import software.amazon.smithy.utils.SetUtils;
import software.amazon.smithy.utils.SmithyBuilder;
import software.amazon.smithy.utils.ToSmithyBuilder;

/**
 * Context object used in plugin execution.
 */
public final class PluginContext implements ToSmithyBuilder {
    private final ProjectionConfig projection;
    private final String projectionName;
    private final Model model;
    private final Model originalModel;
    private final List events;
    private final ObjectNode settings;
    private final FileManifest fileManifest;
    private final ClassLoader pluginClassLoader;
    private final Set sources;
    private Model nonTraitsModel;

    private PluginContext(Builder builder) {
        model = SmithyBuilder.requiredState("model", builder.model);
        fileManifest = SmithyBuilder.requiredState("fileManifest", builder.fileManifest);
        projection = builder.projection;
        projectionName = builder.projectionName;
        originalModel = builder.originalModel;
        events = Collections.unmodifiableList(builder.events);
        settings = builder.settings;
        pluginClassLoader = builder.pluginClassLoader;
        sources = SetUtils.copyOf(builder.sources);
    }

    /**
     * Creates a new PluginContext Builder.
     *
     * @return Returns the created builder.
     */
    public static Builder builder() {
        return new Builder();
    }

    /**
     * @return Get the projection the plugin is optionally attached to.
     */
    public Optional getProjection() {
        return Optional.ofNullable(projection);
    }

    /**
     * Gets the name of the projection being applied.
     *
     * 

If no projection could be found, "source" is assumed. * * @return Returns the explicit or assumed projection name. */ public String getProjectionName() { return projectionName; } /** * Gets the model that was projected. * * @return Get the projected model. */ public Model getModel() { return model; } /** * Get the original model before applying the projection. * * @return The optionally provided original model. */ public Optional getOriginalModel() { return Optional.ofNullable(originalModel); } /** * Gets the validation events encountered after projecting the model. * * @return Get the validation events that were encountered. */ public List getEvents() { return events; } /** * Gets the plugin configuration settings. * * @return Plugins settings object. */ public ObjectNode getSettings() { return settings; } /** * Gets the FileManifest used to create files in the projection. * *

All files written by a plugin should either be written using this * manifest or added to the manifest via {@link FileManifest#addFile}. * * @return Returns the file manifest. */ public FileManifest getFileManifest() { return fileManifest; } /** * Gets the ClassLoader that should be used in build plugins to load * services. * * @return Returns the optionally set ClassLoader. */ public Optional getPluginClassLoader() { return Optional.ofNullable(pluginClassLoader); } /** * Creates a new Model where shapes that define traits or shapes * that are only used as part of a trait definition have been removed. * *

This is typically functionality used by code generators when * generating data structures from a model. It's useful because it only * provides shapes that are used to describe data structures rather than * shapes used to describe metadata about the data structures. * *

Note: this method just calls {@link ModelTransformer#getModelWithoutTraitShapes}. * It's added to {@code PluginContext} to make it more easily available * to code generators. * * @return Returns a Model containing matching shapes. */ public synchronized Model getModelWithoutTraitShapes() { if (nonTraitsModel == null) { nonTraitsModel = ModelTransformer.create().getModelWithoutTraitShapes(model); } return nonTraitsModel; } /** * Gets the source models, or models that are considered the subject * of the build. * *

This does not return an exhaustive set of model paths! There are * typically two kinds of models that are added to a build: source * models and discovered models. Discovered models are someone else's * models. Source models are the models owned by the package being built. * * @return Returns the source models. */ public Set getSources() { return Collections.unmodifiableSet(sources); } /** * Checks if the given shape/ID is either not present in the original * model (thus a new, source shape), or is present and the filename of * the shape in the original model matches one of the defined * {@code sources}. * * @param shape Shape or Shape ID to check. * @return Returns true if this shape is considered a source shape. */ public boolean isSourceShape(ToShapeId shape) { return originalModel == null || isSource(originalModel.getShape(shape.toShapeId()).orElse(null)); } /** * Checks if the given metadata key-value pair is either not present * in the old model (thus a new, source metadata), or is present and * the filename of the entry in the original model matches one of * the defined {@code sources}. * * @param metadataKey Metadata key to check. * @return Returns true if this metadata is considered a source entry. */ public boolean isSourceMetadata(String metadataKey) { return originalModel == null || isSource(originalModel.getMetadataProperty(metadataKey).orElse(null)); } private boolean isSource(FromSourceLocation sourceLocation) { if (sourceLocation == null) { return true; } String location = sourceLocation.getSourceLocation().getFilename(); int offsetFromStart = findOffsetFromStart(location); for (Path path : sources) { String pathString = path.toString(); int offsetFromStartInSource = findOffsetFromStart(pathString); // Compare the strings in a way that normalizes them and strips off protocols. if (location.regionMatches(offsetFromStart, pathString, offsetFromStartInSource, pathString.length())) { return true; } } return false; } private int findOffsetFromStart(String location) { // This accounts for "jar:file:" and "file:". int position = location.indexOf("file:"); return position == -1 ? 0 : position + "file:".length(); } @Override public Builder toBuilder() { return builder() .projection(projectionName, projection) .model(model) .originalModel(originalModel) .events(events) .settings(settings) .fileManifest(fileManifest) .pluginClassLoader(pluginClassLoader) .sources(sources); } /** * Builds a {@link PluginContext}. */ public static final class Builder implements SmithyBuilder { private ProjectionConfig projection; private String projectionName = "source"; private Model model; private Model originalModel; private List events = Collections.emptyList(); private ObjectNode settings = Node.objectNode(); private FileManifest fileManifest; private ClassLoader pluginClassLoader; private Set sources = Collections.emptySet(); private Builder() {} @Override public PluginContext build() { return new PluginContext(this); } /** * Sets the required {@link FileManifest} to use * in the plugin. * * @param fileManifest FileManifest to use. * @return Returns the builder. */ public Builder fileManifest(FileManifest fileManifest) { this.fileManifest = fileManifest; return this; } /** * Sets the required model that is being built. * * @param model Model to set. * @return Returns the builder. */ public Builder model(Model model) { this.model = Objects.requireNonNull(model); return this; } /** * Sets the projection that the plugin belongs to. * * @param name Name of the projection. * @param projection ProjectionConfig to set. * @return Returns the builder. */ public Builder projection(String name, ProjectionConfig projection) { this.projectionName = Objects.requireNonNull(name); this.projection = Objects.requireNonNull(projection); return this; } /** * Sets the model that is being built before it was transformed in * the projection. * * @param originalModel Original Model to set. * @return Returns the builder. */ public Builder originalModel(Model originalModel) { this.originalModel = Objects.requireNonNull(originalModel); return this; } /** * Sets the validation events that occurred after projecting the model. * * @param events Validation events to set. * @return Returns the builder. */ public Builder events(List events) { this.events = Objects.requireNonNull(events); return this; } /** * Sets the settings of the plugin. * * @param settings Settings to set. * @return Returns the builder. */ public Builder settings(ObjectNode settings) { this.settings = Objects.requireNonNull(settings); return this; } /** * Sets a ClassLoader that should be used by build plugins when loading * services. * * @param pluginClassLoader ClassLoader to use in build plugins. * @return Retruns the builder. */ public Builder pluginClassLoader(ClassLoader pluginClassLoader) { this.pluginClassLoader = pluginClassLoader; return this; } /** * Sets the path to models that are considered "source" models of the * package being built. * * @param sources Source models to set. * @return Returns the builder. */ public Builder sources(Collection sources) { this.sources = new HashSet<>(sources); return this; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy