WIP: entity reference based on type-structure

This commit is contained in:
Michael Hoennig 2024-07-08 10:41:30 +02:00
parent 672d4ce0f1
commit ba3667079d
11 changed files with 202 additions and 162 deletions

View File

@ -1,6 +1,8 @@
## HostingAsset Type Structure ## HostingAsset Type Structure
### packages Webspace, Domain, Server ### packages Server, Webspace, Domain
```plantuml ```plantuml
@startuml @startuml
@ -16,6 +18,12 @@ package Booking #99bcdb {
} }
package Hosting #white { package Hosting #white {
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
}
package Webspace #99bcdb { package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER entity HA_UNIX_USER
@ -23,6 +31,7 @@ package Hosting #white {
} }
package Domain #99bcdb { package Domain #99bcdb {
entity HA_DOMAIN_SETUP
entity HA_DOMAIN_DNS_SETUP entity HA_DOMAIN_DNS_SETUP
entity HA_DOMAIN_HTTP_SETUP entity HA_DOMAIN_HTTP_SETUP
entity HA_DOMAIN_EMAIL_SUBMISSION_SETUP entity HA_DOMAIN_EMAIL_SUBMISSION_SETUP
@ -30,27 +39,21 @@ package Hosting #white {
entity HA_EMAIL_ADDRESS entity HA_EMAIL_ADDRESS
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
} }
} BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
BI_CLOUD_SERVER o..> BI_PRIVATE_CLOUD HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
BI_MANAGED_SERVER o..> BI_PRIVATE_CLOUD HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
BI_MANAGED_WEBSPACE o..> BI_MANAGED_SERVER HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_DNS_SETUP *==> BI_DOMAIN_DNS_SETUP HA_DOMAIN_DNS_SETUP ==* BI_DOMAIN_DNS_SETUP
HA_DOMAIN_HTTP_SETUP *==> HA_MANAGED_WEBSPACE HA_DOMAIN_HTTP_SETUP *==> HA_MANAGED_WEBSPACE
HA_DOMAIN_HTTP_SETUP o..> HA_UNIX_USER HA_DOMAIN_HTTP_SETUP o..> HA_UNIX_USER
HA_DOMAIN_EMAIL_SUBMISSION_SETUP *==> BI_DOMAIN_EMAIL_SUBMISSION_SETUP HA_DOMAIN_EMAIL_SUBMISSION_SETUP ==* BI_DOMAIN_EMAIL_SUBMISSION_SETUP
HA_DOMAIN_EMAIL_SUBMISSION_SETUP o..> HA_MANAGED_WEBSPACE HA_DOMAIN_EMAIL_SUBMISSION_SETUP o..> HA_MANAGED_WEBSPACE
HA_DOMAIN_EMAIL_MAILBOX_SETUP *==> HA_MANAGED_WEBSPACE HA_DOMAIN_EMAIL_MAILBOX_SETUP *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
@ -58,8 +61,15 @@ HA_EMAIL_ADDRESS *==> HA_DOMAIN_EMAIL_MAILBOX_SETUP
HA_IP_NUMBER o..> HA_CLOUD_SERVER HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
}
Booking -down[hidden]->Legend
``` ```
### packages Webspace, MariaDB, Server ### packages MariaDB, Server, Webspace
```plantuml ```plantuml
@startuml @startuml
@ -75,12 +85,6 @@ package Booking #99bcdb {
} }
package Hosting #white { package Hosting #white {
package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER
entity HA_EMAIL_ALIAS
}
package MariaDB #99bcdb { package MariaDB #99bcdb {
entity HA_MARIADB_INSTANCE entity HA_MARIADB_INSTANCE
entity HA_MARIADB_USER entity HA_MARIADB_USER
@ -93,15 +97,21 @@ package Hosting #white {
entity HA_IP_NUMBER entity HA_IP_NUMBER
} }
package Webspace #99bcdb {
entity HA_MANAGED_WEBSPACE
entity HA_UNIX_USER
entity HA_EMAIL_ALIAS
} }
BI_CLOUD_SERVER o..> BI_PRIVATE_CLOUD }
BI_MANAGED_SERVER o..> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE o..> BI_MANAGED_SERVER
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
@ -113,8 +123,15 @@ HA_MARIADB_DATABASE o..> HA_MARIADB_INSTANCE
HA_IP_NUMBER o..> HA_CLOUD_SERVER HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
}
Booking -down[hidden]->Legend
``` ```
### packages PostgreSQL, Webspace, Server ### packages Server, PostgreSQL, Webspace
```plantuml ```plantuml
@startuml @startuml
@ -130,6 +147,12 @@ package Booking #99bcdb {
} }
package Hosting #white { package Hosting #white {
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
}
package PostgreSQL #99bcdb { package PostgreSQL #99bcdb {
entity HA_PGSQL_INSTANCE entity HA_PGSQL_INSTANCE
entity HA_PGSQL_USER entity HA_PGSQL_USER
@ -142,21 +165,15 @@ package Hosting #white {
entity HA_EMAIL_ALIAS entity HA_EMAIL_ALIAS
} }
package Server #99bcdb {
entity HA_CLOUD_SERVER
entity HA_MANAGED_SERVER
entity HA_IP_NUMBER
} }
} BI_CLOUD_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_SERVER *--> BI_PRIVATE_CLOUD
BI_MANAGED_WEBSPACE *--> BI_MANAGED_SERVER
BI_CLOUD_SERVER o..> BI_PRIVATE_CLOUD HA_CLOUD_SERVER ==* BI_CLOUD_SERVER
BI_MANAGED_SERVER o..> BI_PRIVATE_CLOUD HA_MANAGED_SERVER ==* BI_MANAGED_SERVER
BI_MANAGED_WEBSPACE o..> BI_MANAGED_SERVER HA_MANAGED_WEBSPACE ==* BI_MANAGED_WEBSPACE
HA_CLOUD_SERVER *==> BI_CLOUD_SERVER
HA_MANAGED_SERVER *==> BI_MANAGED_SERVER
HA_MANAGED_WEBSPACE *==> BI_MANAGED_WEBSPACE
HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER HA_MANAGED_WEBSPACE o..> HA_MANAGED_SERVER
HA_UNIX_USER *==> HA_MANAGED_WEBSPACE HA_UNIX_USER *==> HA_MANAGED_WEBSPACE
HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE HA_EMAIL_ALIAS *==> HA_MANAGED_WEBSPACE
@ -168,5 +185,12 @@ HA_PGSQL_DATABASE o..> HA_PGSQL_INSTANCE
HA_IP_NUMBER o..> HA_CLOUD_SERVER HA_IP_NUMBER o..> HA_CLOUD_SERVER
HA_IP_NUMBER o..> HA_MANAGED_SERVER HA_IP_NUMBER o..> HA_MANAGED_SERVER
HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE HA_IP_NUMBER o..> HA_MANAGED_WEBSPACE
package Legend {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
}
Booking -down[hidden]->Legend
``` ```
#This code generated was by HsHostingAssetType.main, do not amend manually. This code generated was by HsHostingAssetType.main, do not amend manually.

View File

@ -25,7 +25,7 @@ public enum HsBookingItemType implements Node {
@Override @Override
public List<String> edges() { public List<String> edges() {
return ofNullable(parentItemType) return ofNullable(parentItemType)
.map(p -> (nodeName() + " o..> " + p.nodeName())) .map(p -> (nodeName() + " *--> " + p.nodeName()))
.stream().toList(); .stream().toList();
} }

View File

@ -1,5 +1,7 @@
package net.hostsharing.hsadminng.hs.hosting.asset; package net.hostsharing.hsadminng.hs.hosting.asset;
import lombok.AllArgsConstructor;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.booking.item.Node; import net.hostsharing.hsadminng.hs.booking.item.Node;
@ -10,10 +12,13 @@ import java.nio.file.StandardOpenOption;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining; import static java.util.stream.Collectors.joining;
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.*; import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.*;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.OPTIONAL;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED;
public enum HsHostingAssetType implements Node { public enum HsHostingAssetType implements Node {
CLOUD_SERVER( // named e.g. vm1234 CLOUD_SERVER( // named e.g. vm1234
@ -33,9 +38,10 @@ public enum HsHostingAssetType implements Node {
inGroup("Webspace"), inGroup("Webspace"),
requiredParent(MANAGED_WEBSPACE)), requiredParent(MANAGED_WEBSPACE)),
// DOMAIN_SETUP( // named e.g. example.org @Deprecated
// inGroup("Domain") DOMAIN_SETUP( // named e.g. example.org
// ), inGroup("Domain")
),
DOMAIN_DNS_SETUP( // named e.g. example.org DOMAIN_DNS_SETUP( // named e.g. example.org
inGroup("Domain"), inGroup("Domain"),
@ -101,11 +107,11 @@ public enum HsHostingAssetType implements Node {
); );
final String groupName; final String groupName;
private final EntityTypeRelation<?>[] relations; private final EntityTypeRelation<?, ?>[] relations;
HsHostingAssetType( HsHostingAssetType(
final String groupName, final String groupName,
final EntityTypeRelation<?>... relations final EntityTypeRelation<?, ?>... relations
) { ) {
this.groupName = groupName; this.groupName = groupName;
this.relations = relations; this.relations = relations;
@ -116,6 +122,45 @@ public enum HsHostingAssetType implements Node {
return groupName; return groupName;
} }
public RelationPolicy bookingItemPolicy() {
return stream(relations).filter(r -> r.relatedType == (Object) HsBookingItemType.class).findAny()
.map(r -> r.relationType)
.orElse(RelationPolicy.FORBIDDEN);
}
public HsBookingItemType bookingItemType() {
return stream(relations).filter(r -> r.relatedType == (Object) HsBookingItemType.class).findAny()
.map(r -> HsBookingItemType.valueOf(r.relatedType.toString()))
.orElse(null);
}
public RelationPolicy parentAssetPolicy() {
return stream(relations).filter(r -> r.relatedType == (Object) HsHostingAssetType.class).findAny()
.map(r -> r.relationType)
.orElse(RelationPolicy.FORBIDDEN);
}
public HsHostingAssetType parentAssetType() {
return stream(relations).filter(r -> r.relatedType == (Object) HsHostingAssetType.class).findAny()
.map(r -> HsHostingAssetType.valueOf(r.relatedType.toString()))
.orElse(null);
}
public RelationPolicy assignedToAssetPolicy() {
return stream(relations).filter(r -> r.relatedType == (Object) HsHostingAssetType.class).findAny()
.map(r -> r.relationType)
.orElse(RelationPolicy.FORBIDDEN);
}
public HsHostingAssetType assignedToAssetType() {
return stream(relations).filter(r -> r.relatedType == (Object) HsHostingAssetType.class).findAny()
.map(r -> HsHostingAssetType.valueOf(r.relatedType.toString()))
.orElse(null);
}
@Override @Override
public List<String> edges() { public List<String> edges() {
return stream(relations) return stream(relations)
@ -176,6 +221,13 @@ public enum HsHostingAssetType implements Node {
%{bookingItemEdges} %{bookingItemEdges}
%{hostingAssetEdges} %{hostingAssetEdges}
package Legend {
SUB_ENTITY1 *--> REQUIRED_PARENT_ENTITY
SUB_ENTITY2 *..> OPTIONAL_PARENT_ENTITY
ASSIGNED_ENTITY1 o--> REQUIRED_ASSIGNED_TO_ENTITY1
ASSIGNED_ENTITY2 o..> OPTIONAL_ASSIGNED_TO_ENTITY2
}
Booking -down[hidden]->Legend
``` ```
""" """
.replace("%{packages}", String.join(", ", includedHostingGroups)) .replace("%{packages}", String.join(", ", includedHostingGroups))
@ -201,6 +253,8 @@ public enum HsHostingAssetType implements Node {
Files.writeString( Files.writeString(
Path.of("doc/hs-hosting-asset-type-structure.md"), Path.of("doc/hs-hosting-asset-type-structure.md"),
""" """
## HostingAsset Type Structure ## HostingAsset Type Structure
""", """,
@ -210,52 +264,48 @@ public enum HsHostingAssetType implements Node {
// .map(t -> t.groupName) // .map(t -> t.groupName)
// .collect(toSet())); // .collect(toSet()));
renderAsPlantUML(Set.of("Domain", "Server", "Webspace")); renderAsPlantUML(Set.of("Domain", "Webspace", "Server"));
renderAsPlantUML(Set.of("Server", "Webspace", "MariaDB")); renderAsPlantUML(Set.of("MariaDB", "Webspace", "Server"));
renderAsPlantUML(Set.of("Server", "Webspace", "PostgreSQL")); renderAsPlantUML(Set.of("PostgreSQL", "Webspace", "Server"));
Files.writeString( Files.writeString(
Path.of("doc/hs-hosting-asset-type-structure.md"), Path.of("doc/hs-hosting-asset-type-structure.md"),
""" """
#This code generated was by %{this}.main, do not amend manually. This code generated was by %{this}.main, do not amend manually.
""" """
.replace("%{this}", HsHostingAssetType.class.getSimpleName()), .replace("%{this}", HsHostingAssetType.class.getSimpleName()),
StandardOpenOption.APPEND); StandardOpenOption.APPEND);
} }
public enum RelationPolicy {
FORBIDDEN, OPTIONAL, REQUIRED
}
} }
enum TypeRelationType { @AllArgsConstructor
OPTIONAL, REQUIRED class EntityTypeRelation<E, T extends Node> {
} final HsHostingAssetType.RelationPolicy relationType;
private final Function<HsHostingAssetEntity, E> getter;
class EntityTypeRelation<T extends Node> {
final String edge;
final TypeRelationType relationType;
final T relatedType; final T relatedType;
final String edge;
EntityTypeRelation(final String edge, final TypeRelationType required, final T relatedType) { static EntityTypeRelation<HsBookingItemEntity, HsBookingItemType> requires(final HsBookingItemType bookingItemType) {
this.edge = edge; return new EntityTypeRelation<>(REQUIRED, HsHostingAssetEntity::getBookingItem, bookingItemType, " ==* ");
this.relationType = required;
this.relatedType = relatedType;
} }
static EntityTypeRelation<HsBookingItemType> requires(final HsBookingItemType bookingItemType) { static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> optionalParent(final HsHostingAssetType hostingAssetType) {
return new EntityTypeRelation<>(" *==> ", TypeRelationType.REQUIRED, bookingItemType); return new EntityTypeRelation<>(OPTIONAL, null, hostingAssetType, " o..> ");
} }
static EntityTypeRelation<HsHostingAssetType> optionalParent(final HsHostingAssetType hostingAssetType) { static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> requiredParent(final HsHostingAssetType hostingAssetType) {
return new EntityTypeRelation<>(" o..> ", TypeRelationType.OPTIONAL, hostingAssetType); return new EntityTypeRelation<>(REQUIRED, null, hostingAssetType, " *==> ");
} }
static EntityTypeRelation<HsHostingAssetType> requiredParent(final HsHostingAssetType hostingAssetType) { static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> assignedTo(final HsHostingAssetType hostingAssetType) {
return new EntityTypeRelation<>(" *==> ", TypeRelationType.REQUIRED, hostingAssetType); return new EntityTypeRelation<>(REQUIRED, null, hostingAssetType, " o..> ");
} }
static EntityTypeRelation<HsHostingAssetType> assignedTo(final HsHostingAssetType hostingAssetType) { static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> optionallyAssignedTo(final HsHostingAssetType hostingAssetType) {
return new EntityTypeRelation<>(" o..> ", TypeRelationType.REQUIRED, hostingAssetType); return new EntityTypeRelation<>(OPTIONAL, null, hostingAssetType, " o..> ");
}
static EntityTypeRelation<HsHostingAssetType> optionallyAssignedTo(final HsHostingAssetType hostingAssetType) {
return new EntityTypeRelation<>(" o..> ", TypeRelationType.OPTIONAL, hostingAssetType);
} }
} }

View File

@ -1,7 +1,7 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators; package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -9,9 +9,7 @@ class HsCloudServerHostingAssetValidator extends HsHostingAssetEntityValidator {
HsCloudServerHostingAssetValidator() { HsCloudServerHostingAssetValidator() {
super( super(
BookingItem.mustBeOfType(HsBookingItemType.CLOUD_SERVER), HsHostingAssetType.CLOUD_SERVER,
ParentAsset.mustBeNull(),
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), AlarmContact.isOptional(),
NO_EXTRA_PROPERTIES); NO_EXTRA_PROPERTIES);
} }

View File

@ -9,6 +9,7 @@ import java.util.regex.Pattern;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_DNS_SETUP;
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf; import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty; import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty; import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
@ -31,9 +32,8 @@ class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidato
RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT; RR_REGEX_NAME + RR_REGEX_IN + RR_REGEX_TTL + RR_RECORD_TYPE + RR_RECORD_DATA + RR_COMMENT;
HsDomainDnsSetupHostingAssetValidator() { HsDomainDnsSetupHostingAssetValidator() {
super( BookingItem.mustBeNull(), super(
ParentAsset.mustBeNull(), DOMAIN_DNS_SETUP,
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), AlarmContact.isOptional(),
integerProperty("TTL").min(0).withDefault(21600), integerProperty("TTL").min(0).withDefault(21600),

View File

@ -4,6 +4,8 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator { class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
public static final String DOMAIN_NAME_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}"; public static final String DOMAIN_NAME_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}";
@ -11,9 +13,7 @@ class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
private final Pattern identifierPattern; private final Pattern identifierPattern;
HsDomainSetupHostingAssetValidator() { HsDomainSetupHostingAssetValidator() {
super( BookingItem.mustBeNull(), super( DOMAIN_SETUP,
ParentAsset.mustBeNull(),
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), AlarmContact.isOptional(),
NO_EXTRA_PROPERTIES); NO_EXTRA_PROPERTIES);

View File

@ -15,9 +15,7 @@ class HsEMailAliasHostingAssetValidator extends HsHostingAssetEntityValidator {
public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322 public static final int EMAIL_ADDRESS_MAX_LENGTH = 320; // according to RFC 5321 and RFC 5322
HsEMailAliasHostingAssetValidator() { HsEMailAliasHostingAssetValidator() {
super( BookingItem.mustBeNull(), super( HsHostingAssetType.EMAIL_ALIAS,
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_WEBSPACE),
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), AlarmContact.isOptional(),
arrayOf( arrayOf(

View File

@ -9,7 +9,6 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.validation.HsEntityValidator; import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
import net.hostsharing.hsadminng.hs.validation.ValidatableProperty; import net.hostsharing.hsadminng.hs.validation.ValidatableProperty;
import jakarta.validation.constraints.NotNull;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@ -21,26 +20,36 @@ import java.util.stream.Stream;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.FORBIDDEN;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED;
public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<HsHostingAssetEntity> { public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<HsHostingAssetEntity> {
static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0]; static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0];
private final HsHostingAssetEntityValidator.BookingItem bookingItemValidation; private final ReferenceValidator<HsBookingItemEntity, HsBookingItemType> bookingItemReferenceValidation;
private final HsHostingAssetEntityValidator.ParentAsset parentAssetValidation; private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> parentAssetReferenceValidation;
private final HsHostingAssetEntityValidator.AssignedToAsset assignedToAssetValidation; private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> assignedToAssetReferenceValidation;
private final HsHostingAssetEntityValidator.AlarmContact alarmContactValidation; private final HsHostingAssetEntityValidator.AlarmContact alarmContactValidation;
HsHostingAssetEntityValidator( HsHostingAssetEntityValidator(
@NotNull final BookingItem bookingItemValidation, final HsHostingAssetType assetType, final AlarmContact alarmContactValidation, final ValidatableProperty<?, ?>... properties) {
@NotNull final ParentAsset parentAssetValidation,
@NotNull final AssignedToAsset assignedToAssetValidation,
@NotNull final AlarmContact alarmContactValidation,
final ValidatableProperty<?, ?>... properties) {
super(properties); super(properties);
this.bookingItemValidation = bookingItemValidation; this.bookingItemReferenceValidation = new ReferenceValidator<>(
this.parentAssetValidation = parentAssetValidation; assetType.bookingItemPolicy(),
this.assignedToAssetValidation = assignedToAssetValidation; assetType.bookingItemType(),
HsHostingAssetEntity::getBookingItem,
HsBookingItemEntity::getType);
this.parentAssetReferenceValidation = new ReferenceValidator<>(
assetType.parentAssetPolicy(),
assetType.parentAssetType(),
HsHostingAssetEntity::getParentAsset,
HsHostingAssetEntity::getType);
this.assignedToAssetReferenceValidation = new ReferenceValidator<>(
assetType.assignedToAssetPolicy(),
assetType.assignedToAssetType(),
HsHostingAssetEntity::getAssignedToAsset,
HsHostingAssetEntity::getType);
this.alarmContactValidation = alarmContactValidation; this.alarmContactValidation = alarmContactValidation;
} }
@ -63,9 +72,9 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
private List<String> validateEntityReferencesAndProperties(final HsHostingAssetEntity assetEntity) { private List<String> validateEntityReferencesAndProperties(final HsHostingAssetEntity assetEntity) {
return Stream.of( return Stream.of(
validateReferencedEntity(assetEntity, "bookingItem", bookingItemValidation::validate), validateReferencedEntity(assetEntity, "bookingItem", bookingItemReferenceValidation::validate),
validateReferencedEntity(assetEntity, "parentAsset", parentAssetValidation::validate), validateReferencedEntity(assetEntity, "parentAsset", parentAssetReferenceValidation::validate),
validateReferencedEntity(assetEntity, "assignedToAsset", assignedToAssetValidation::validate), validateReferencedEntity(assetEntity, "assignedToAsset", assignedToAssetReferenceValidation::validate),
validateReferencedEntity(assetEntity, "alarmContact", alarmContactValidation::validate), validateReferencedEntity(assetEntity, "alarmContact", alarmContactValidation::validate),
validateProperties(assetEntity)) validateProperties(assetEntity))
.filter(Objects::nonNull) .filter(Objects::nonNull)
@ -137,15 +146,15 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
protected abstract Pattern identifierPattern(HsHostingAssetEntity assetEntity); protected abstract Pattern identifierPattern(HsHostingAssetEntity assetEntity);
static abstract class ReferenceValidator<S, T> { static class ReferenceValidator<S, T> {
private final Policy policy; private final HsHostingAssetType.RelationPolicy policy;
private final T subEntityType; private final T subEntityType;
private final Function<HsHostingAssetEntity, S> subEntityGetter; private final Function<HsHostingAssetEntity, S> subEntityGetter;
private final Function<S,T> subEntityTypeGetter; private final Function<S,T> subEntityTypeGetter;
public ReferenceValidator( public ReferenceValidator(
final Policy policy, final HsHostingAssetType.RelationPolicy policy,
final T subEntityType, final T subEntityType,
final Function<HsHostingAssetEntity, S> subEntityGetter, final Function<HsHostingAssetEntity, S> subEntityGetter,
final Function<S, T> subEntityTypeGetter) { final Function<S, T> subEntityTypeGetter) {
@ -156,7 +165,7 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
} }
public ReferenceValidator( public ReferenceValidator(
final Policy policy, final HsHostingAssetType.RelationPolicy policy,
final Function<HsHostingAssetEntity, S> subEntityGetter) { final Function<HsHostingAssetEntity, S> subEntityGetter) {
this.policy = policy; this.policy = policy;
this.subEntityType = null; this.subEntityType = null;
@ -164,17 +173,13 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
this.subEntityTypeGetter = e -> null; this.subEntityTypeGetter = e -> null;
} }
enum Policy {
OPTIONAL, FORBIDDEN, REQUIRED
}
List<String> validate(final HsHostingAssetEntity assetEntity, final String referenceFieldName) { List<String> validate(final HsHostingAssetEntity assetEntity, final String referenceFieldName) {
final var subEntity = subEntityGetter.apply(assetEntity); final var subEntity = subEntityGetter.apply(assetEntity);
if (policy == Policy.REQUIRED && subEntity == null) { if (policy == REQUIRED && subEntity == null) {
return List.of(referenceFieldName + "' must not be null but is null"); return List.of(referenceFieldName + "' must not be null but is null");
} }
if (policy == Policy.FORBIDDEN && subEntity != null) { if ((policy == FORBIDDEN) && (subEntity != null)) {
return List.of(referenceFieldName + "' must be null but is set to "+ assetEntity.getBookingItem().toShortString()); return List.of(referenceFieldName + "' must be null but is set to "+ assetEntity.getBookingItem().toShortString());
} }
final var subItemType = subEntity != null ? subEntityTypeGetter.apply(subEntity) : null; final var subItemType = subEntity != null ? subEntityTypeGetter.apply(subEntity) : null;
@ -185,59 +190,28 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
} }
} }
static class BookingItem extends ReferenceValidator<HsBookingItemEntity, HsBookingItemType> { static class ParentAssetReferenceValidation extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
BookingItem(final Policy policy, final HsBookingItemType bookingItemType) { ParentAssetReferenceValidation(final HsHostingAssetType.RelationPolicy policy, final HsHostingAssetType parentAssetType) {
super(policy, bookingItemType, HsHostingAssetEntity::getBookingItem, HsBookingItemEntity::getType);
}
static BookingItem mustBeNull() {
return new BookingItem(Policy.FORBIDDEN, null);
}
static BookingItem mustBeOfType(final HsBookingItemType hsBookingItemType) {
return new BookingItem(Policy.REQUIRED, hsBookingItemType);
}
}
static class ParentAsset extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
ParentAsset(final ReferenceValidator.Policy policy, final HsHostingAssetType parentAssetType) {
super(policy, parentAssetType, HsHostingAssetEntity::getParentAsset, HsHostingAssetEntity::getType); super(policy, parentAssetType, HsHostingAssetEntity::getParentAsset, HsHostingAssetEntity::getType);
} }
static ParentAsset mustBeNull() {
return new ParentAsset(Policy.FORBIDDEN, null);
} }
static ParentAsset mustBeOfType(final HsHostingAssetType hostingAssetType) { static class AssignedToAssetReferenceValidation extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
return new ParentAsset(Policy.REQUIRED, hostingAssetType);
}
static ParentAsset mustBeNullOrOfType(final HsHostingAssetType hostingAssetType) { AssignedToAssetReferenceValidation(final HsHostingAssetType.RelationPolicy policy, final HsHostingAssetType assignedToAssetType) {
return new ParentAsset(Policy.OPTIONAL, hostingAssetType);
}
}
static class AssignedToAsset extends ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> {
AssignedToAsset(final ReferenceValidator.Policy policy, final HsHostingAssetType assignedToAssetType) {
super(policy, assignedToAssetType, HsHostingAssetEntity::getAssignedToAsset, HsHostingAssetEntity::getType); super(policy, assignedToAssetType, HsHostingAssetEntity::getAssignedToAsset, HsHostingAssetEntity::getType);
} }
static AssignedToAsset mustBeNull() {
return new AssignedToAsset(Policy.FORBIDDEN, null);
}
} }
static class AlarmContact extends ReferenceValidator<HsOfficeContactEntity, Enum<?>> { static class AlarmContact extends ReferenceValidator<HsOfficeContactEntity, Enum<?>> {
AlarmContact(final ReferenceValidator.Policy policy) { AlarmContact(final HsHostingAssetType.RelationPolicy policy) {
super(policy, HsHostingAssetEntity::getAlarmContact); super(policy, HsHostingAssetEntity::getAlarmContact);
} }
static AlarmContact isOptional() { static AlarmContact isOptional() {
return new AlarmContact(Policy.OPTIONAL); return new AlarmContact(HsHostingAssetType.RelationPolicy.OPTIONAL);
} }
} }

View File

@ -1,10 +1,10 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators; package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty; import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty; import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty; import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
@ -13,9 +13,7 @@ class HsManagedServerHostingAssetValidator extends HsHostingAssetEntityValidator
public HsManagedServerHostingAssetValidator() { public HsManagedServerHostingAssetValidator() {
super( super(
BookingItem.mustBeOfType(HsBookingItemType.MANAGED_SERVER), MANAGED_SERVER,
ParentAsset.mustBeNull(), // until we introduce a hosting asset for 'HOST'
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), // hostmaster alert address is implicitly added AlarmContact.isOptional(), // hostmaster alert address is implicitly added
// monitoring // monitoring

View File

@ -1,16 +1,15 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators; package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity; import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator { class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator {
public HsManagedWebspaceHostingAssetValidator() { public HsManagedWebspaceHostingAssetValidator() {
super(BookingItem.mustBeOfType(HsBookingItemType.MANAGED_WEBSPACE), super(
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_SERVER), // the (shared or private) ManagedServer MANAGED_SERVER,
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), // hostmaster alert address is implicitly added AlarmContact.isOptional(), // hostmaster alert address is implicitly added
NO_EXTRA_PROPERTIES); NO_EXTRA_PROPERTIES);
} }

View File

@ -17,9 +17,8 @@ class HsUnixUserHostingAssetValidator extends HsHostingAssetEntityValidator {
private static final int DASH_LENGTH = "-".length(); private static final int DASH_LENGTH = "-".length();
HsUnixUserHostingAssetValidator() { HsUnixUserHostingAssetValidator() {
super( BookingItem.mustBeNull(), super(
ParentAsset.mustBeOfType(HsHostingAssetType.MANAGED_WEBSPACE), HsHostingAssetType.DOMAIN_DNS_SETUP,
AssignedToAsset.mustBeNull(),
AlarmContact.isOptional(), AlarmContact.isOptional(),
integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(), integerProperty("SSD hard quota").unit("GB").maxFrom("SSD").optional(),