1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
54
55
56
57
58
59
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
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
218
219
220
221
222
223
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 }