View Javadoc
1   /*
2    * Copyright (c) 2022-2023. Roland T. Lichti, Kaiserpfalz EDV-Service.
3    *
4    * This program is free software: you can redistribute it and/or modify
5    * it under the terms of the GNU General Public License as published by
6    * the Free Software Foundation, either version 3 of the License, or
7    * (at your option) any later version.
8    *
9    * This program is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU General Public License
15   * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16   */
17  
18  package de.kaiserpfalzedv.commons.core.resources;
19  
20  import java.time.OffsetDateTime;
21  import java.time.ZoneOffset;
22  import java.util.HashMap;
23  import java.util.Map;
24  import java.util.Optional;
25  import java.util.UUID;
26  
27  import org.eclipse.microprofile.openapi.annotations.media.Schema;
28  import org.hibernate.boot.MetadataBuilder;
29  
30  import com.fasterxml.jackson.annotation.JsonIgnore;
31  import com.fasterxml.jackson.annotation.JsonInclude;
32  import com.fasterxml.jackson.annotation.JsonPropertyOrder;
33  
34  import de.kaiserpfalzedv.commons.api.resources.HasId;
35  import de.kaiserpfalzedv.commons.api.resources.Metadata;
36  import de.kaiserpfalzedv.commons.api.resources.Pointer;
37  import de.kaiserpfalzedv.commons.api.resources.TimeStampPattern;
38  import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
39  import jakarta.validation.constraints.Max;
40  import jakarta.validation.constraints.Min;
41  import jakarta.validation.constraints.NotNull;
42  import jakarta.validation.constraints.Pattern;
43  import jakarta.validation.constraints.Size;
44  import lombok.AllArgsConstructor;
45  import lombok.Builder;
46  import lombok.EqualsAndHashCode;
47  import lombok.Getter;
48  import lombok.NoArgsConstructor;
49  import lombok.ToString;
50  import lombok.extern.jackson.Jacksonized;
51  
52  /**
53   * Metadata -- common data for every resource of the system.
54   * <p>
55   * Default values for the lombok builder are set in {@link MetadataBuilder}.
56   *
57   * @author klenkes74 {@literal <rlichti@kaiserpfalz-edv.de>}
58   * @since 2.0.0  2021-05-24
59   * @version 2.0.2 2022-01-04
60   */
61  @SuppressFBWarnings(value = "EI_EXPOSE_REF2", justification = "Use of lombok provided builder.")
62  @Jacksonized
63  @Builder(toBuilder = true)
64  @AllArgsConstructor
65  @NoArgsConstructor
66  @Getter
67  @ToString(onlyExplicitlyIncluded = true)
68  @EqualsAndHashCode(onlyExplicitlyIncluded = true)
69  @JsonInclude(JsonInclude.Include.NON_ABSENT)
70  @JsonPropertyOrder({"identity,uid,generation,owner,created,deleted,annotations,labels,selfLink"})
71  @Schema(
72          name = "ResourceMetadata",
73          description = "The metadata of a resource."
74  )
75  public class MetadataImpl implements Metadata {
76      /** serial class version */
77      private static final long serialVersionUID = 0L;
78  
79      @Schema(
80              name = "identity",
81              description = "This is the identity of the resource.",
82              implementation = Pointer.class
83      )
84      @ToString.Include
85      @EqualsAndHashCode.Include
86      @NotNull
87      private de.kaiserpfalzedv.commons.core.resources.PointerImpl identity;
88  
89      @Schema(
90              name = "uid",
91              description = "The unique identifier of this resource",
92              required = true,
93              minLength = HasId.MIN_LENGTH,
94              maxLength = HasId.MAX_LENGTH,
95              pattern = HasId.VALID_ID_PATTERN,
96              example = HasId.VALID_ID_EXAMPLE,
97              defaultValue = "random UUID"
98      )
99      @ToString.Include
100     @EqualsAndHashCode.Include
101     @Builder.Default
102     @NotNull
103     private final UUID uid = UUID.randomUUID();
104 
105     @Schema(
106             name = "generation",
107             description = "The generation of this object. Every change adds 1.",
108             required = true,
109             example = "0",
110             defaultValue = "0",
111             minimum = "0",
112             maxItems = Integer.MAX_VALUE
113     )
114     @ToString.Include
115     @Builder.Default
116     @NotNull
117     @Min(value = 0, message = "The generation must be at least 0.")
118     @Max(value = Integer.MAX_VALUE, message = "The generation must not be bigger than " + Integer.MAX_VALUE + ".")
119     private final Integer generation = 0;
120 
121     @Schema(
122             name = "owner",
123             description = "The owning resource. This is a sub-resource or managed resource of the given address.",
124             nullable = true,
125             implementation = Pointer.class
126     )
127     @Builder.Default
128     private final de.kaiserpfalzedv.commons.core.resources.PointerImpl owner = null;
129 
130     @Schema(
131             name = "created",
132             description = "The timestamp of resource creation.",
133             required = true,
134             defaultValue = "now",
135             example = TimeStampPattern.VALID_EXAMPLE,
136             pattern = TimeStampPattern.VALID_PATTERN,
137             minLength = TimeStampPattern.VALID_LENGTH,
138             maxLength = TimeStampPattern.VALID_LENGTH
139     )
140     @Builder.Default
141     @Size(min = TimeStampPattern.VALID_LENGTH, max = TimeStampPattern.VALID_LENGTH, message = TimeStampPattern.VALID_LENGTH_MSG)
142     @Pattern(regexp = TimeStampPattern.VALID_PATTERN, message = TimeStampPattern.VALID_PATTERN_MSG)
143     protected OffsetDateTime created = OffsetDateTime.now(ZoneOffset.UTC);
144 
145     @Schema(
146             name = "modified",
147             description = "The timestamp of the last change.",
148             required = true,
149             defaultValue = "now",
150             example = TimeStampPattern.VALID_EXAMPLE,
151             pattern = TimeStampPattern.VALID_PATTERN,
152             minLength = TimeStampPattern.VALID_LENGTH,
153             maxLength = TimeStampPattern.VALID_LENGTH
154     )
155     @Builder.Default
156     @Size(min = TimeStampPattern.VALID_LENGTH, max = TimeStampPattern.VALID_LENGTH, message = TimeStampPattern.VALID_LENGTH_MSG)
157     @Pattern(regexp = TimeStampPattern.VALID_PATTERN, message = TimeStampPattern.VALID_PATTERN_MSG)
158     protected OffsetDateTime modified = OffsetDateTime.now(ZoneOffset.UTC);
159 
160     @Schema(
161             name = "deleted",
162             description = "The timestamp of object deletion. Marks an object to be deleted.",
163             nullable = true,
164             defaultValue = "null",
165             example = TimeStampPattern.VALID_EXAMPLE,
166             pattern = TimeStampPattern.VALID_PATTERN,
167             minLength = TimeStampPattern.VALID_LENGTH,
168             maxLength = TimeStampPattern.VALID_LENGTH
169     )
170     @Builder.Default
171     private final OffsetDateTime deleted = null;
172 
173     @Schema(
174             name = "annotations",
175             description = "A set of annotations to this resource.",
176             nullable = true,
177             minItems = 0,
178             maxItems = 256
179     )
180     @Builder.Default
181     @SuppressFBWarnings(value = {"EI_EXPOSE_REP","EI_EXPOSE_REP2"}, justification = "lombok provided @Getter are created")
182     private final Map<String, String> annotations = new HashMap<>();
183 
184     @Schema(
185             name = "labels",
186             description = "A set of labels to this resource.",
187             nullable = true,
188             minItems = 0,
189             maxItems = 256
190     )
191     @Builder.Default
192     @SuppressFBWarnings(value = {"EI_EXPOSE_REP","EI_EXPOSE_REP2"}, justification = "lombok provided @Getter are created")
193     private final Map<String, String> labels = new HashMap<>();
194 
195 
196     @Override
197     @JsonIgnore
198     public Optional<OffsetDateTime> getDeletionTimestamp() {
199         return Optional.ofNullable(this.deleted);
200     }
201 
202     @Override
203     @JsonIgnore
204     public Optional<de.kaiserpfalzedv.commons.api.resources.Pointer> getOwningResource() {
205         return Optional.ofNullable(this.owner);
206     }
207 
208     @Override
209     public MetadataImpl increaseGeneration() {
210         return this.toBuilder()
211                 .generation(this.generation + 1)
212                 .build();
213     }
214 
215 
216     /**
217      * Generates a metadata builder with the given identity.
218      *
219      * @param kind       the kind of resource.
220      * @param apiVersion the api version of the resource.
221      * @param nameSpace  the namespace of the resource.
222      * @param name       the name of the resource.
223      * @return A metadata builder for adding the other metadata.
224      */
225     public static MetadataImplBuilder of(
226             final String kind,
227             final String apiVersion,
228             final String nameSpace,
229             final String name
230     ) {
231         return MetadataImpl.builder()
232                 .identity(
233                         de.kaiserpfalzedv.commons.core.resources.PointerImpl.builder()
234                                 .kind(kind)
235                                 .apiVersion(apiVersion)
236                                 .nameSpace(nameSpace)
237                                 .name(name)
238                                 .build()
239                 );
240     }
241 
242 
243     @SuppressWarnings("MethodDoesntCallSuperMethod")
244     @SuppressFBWarnings(value = "CN_IDIOM_NO_SUPER_CALL", justification = "Using the lombok builder.")
245     @Override
246     public MetadataImpl clone() {
247         return this.toBuilder().build();
248     }
249 }