001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      https://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.release.plugin.slsa.v1_2;
018
019import java.util.Map;
020import java.util.Objects;
021
022import com.fasterxml.jackson.annotation.JsonInclude;
023import com.fasterxml.jackson.annotation.JsonProperty;
024
025/**
026 * Description of an artifact or resource referenced in the build, identified by URI and cryptographic digest.
027 *
028 * <p>
029 * Used to represent inputs to, outputs from, or byproducts of the build process.
030 * </p>
031 *
032 * @see <a href="https://slsa.dev/spec/v1.2">SLSA v1.2 Specification</a>
033 * @since 1.10.0
034 */
035@JsonInclude(JsonInclude.Include.NON_NULL)
036public class ResourceDescriptor {
037
038    /** Additional key-value metadata about the resource. */
039    @JsonProperty("annotations")
040    private Map<String, Object> annotations;
041    /** Raw contents of the resource, base64-encoded in JSON. */
042    @JsonProperty("content")
043    private byte[] content;
044    /** Map of digest algorithm names to hex-encoded values. */
045    @JsonProperty("digest")
046    private Map<String, String> digest;
047    /** Download URI for the resource, if different from {@link #uri}. */
048    @JsonProperty("downloadLocation")
049    private String downloadLocation;
050    /** Media type of the resource. */
051    @JsonProperty("mediaType")
052    private String mediaType;
053    /** Human-readable name of the resource. */
054    @JsonProperty("name")
055    private String name;
056    /** URI identifying the resource. */
057    @JsonProperty("uri")
058    private String uri;
059
060    /** Creates a new ResourceDescriptor instance. */
061    public ResourceDescriptor() {
062    }
063
064    /**
065     * Creates a new ResourceDescriptor with the given URI and digest.
066     *
067     * @param uri    URI identifying the resource.
068     * @param digest map of digest algorithm names to their hex-encoded values.
069     */
070    public ResourceDescriptor(final String uri, final Map<String, String> digest) {
071        this.uri = uri;
072        this.digest = digest;
073    }
074
075    @Override
076    public boolean equals(final Object o) {
077        if (this == o) {
078            return true;
079        }
080        if (o == null || getClass() != o.getClass()) {
081            return false;
082        }
083        final ResourceDescriptor that = (ResourceDescriptor) o;
084        return Objects.equals(uri, that.uri) && Objects.equals(digest, that.digest);
085    }
086
087    /**
088     * Gets additional key-value metadata about the resource, such as filename, size, or builder-specific attributes.
089     *
090     * @return The annotations map, or {@code null} if not set.
091     */
092    public Map<String, Object> getAnnotations() {
093        return annotations;
094    }
095
096    /**
097     * Gets the raw contents of the resource, base64-encoded when serialized to JSON.
098     *
099     * @return The resource content, or {@code null} if not set.
100     */
101    public byte[] getContent() {
102        return content;
103    }
104
105    /**
106     * Gets the map of cryptographic digest algorithms to their corresponding hex-encoded values for this resource.
107     *
108     * <p>
109     * Common keys include {@code "sha256"} and {@code "sha512"}.
110     * </p>
111     *
112     * @return The digest map, or {@code null} if not set.
113     */
114    public Map<String, String> getDigest() {
115        return digest;
116    }
117
118    /**
119     * Gets the download URI for the resource, if different from {@link #getUri()}.
120     *
121     * @return The download location URI, or {@code null} if not set.
122     */
123    public String getDownloadLocation() {
124        return downloadLocation;
125    }
126
127    /**
128     * Gets the media type of the resource (for example, {@code "application/octet-stream"}).
129     *
130     * @return The media type, or {@code null} if not set.
131     */
132    public String getMediaType() {
133        return mediaType;
134    }
135
136    /**
137     * Gets the name of the resource.
138     *
139     * @return The resource name, or {@code null} if not set.
140     */
141    public String getName() {
142        return name;
143    }
144
145    /**
146     * Gets the URI identifying the resource.
147     *
148     * @return The resource URI, or {@code null} if not set.
149     */
150    public String getUri() {
151        return uri;
152    }
153
154    @Override
155    public int hashCode() {
156        return Objects.hash(uri, digest);
157    }
158
159    /**
160     * Sets additional key-value metadata about the resource.
161     *
162     * @param annotations The annotations map.
163     * @return this for chaining.
164     */
165    public ResourceDescriptor setAnnotations(final Map<String, Object> annotations) {
166        this.annotations = annotations;
167        return this;
168    }
169
170    /**
171     * Sets the raw contents of the resource.
172     *
173     * @param content The resource content.
174     * @return this for chaining.
175     */
176    public ResourceDescriptor setContent(final byte[] content) {
177        this.content = content;
178        return this;
179    }
180
181    /**
182     * Sets the map of cryptographic digest algorithms to their hex-encoded values.
183     *
184     * @param digest The digest map.
185     * @return this for chaining.
186     */
187    public ResourceDescriptor setDigest(final Map<String, String> digest) {
188        this.digest = digest;
189        return this;
190    }
191
192    /**
193     * Sets the download URI for the resource.
194     *
195     * @param downloadLocation The download location URI.
196     * @return this for chaining.
197     */
198    public ResourceDescriptor setDownloadLocation(final String downloadLocation) {
199        this.downloadLocation = downloadLocation;
200        return this;
201    }
202
203    /**
204     * Sets the media type of the resource.
205     *
206     * @param mediaType The media type.
207     * @return this for chaining.
208     */
209    public ResourceDescriptor setMediaType(final String mediaType) {
210        this.mediaType = mediaType;
211        return this;
212    }
213
214    /**
215     * Sets the name of the resource.
216     *
217     * @param name The resource name.
218     * @return this for chaining.
219     */
220    public ResourceDescriptor setName(final String name) {
221        this.name = name;
222        return this;
223    }
224
225    /**
226     * Sets the URI identifying the resource.
227     *
228     * @param uri The resource URI.
229     * @return this for chaining.
230     */
231    public ResourceDescriptor setUri(final String uri) {
232        this.uri = uri;
233        return this;
234    }
235
236    @Override
237    public String toString() {
238        return "ResourceDescriptor{uri='" + uri + "', digest=" + digest + '}';
239    }
240}