add-ipnumber-validatation (#77)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/77 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.item;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
|
||||
@ -21,12 +22,17 @@ public enum HsBookingItemType implements Node {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> edges() {
|
||||
public List<String> edges(final Set<String> inGroups) {
|
||||
return ofNullable(parentItemType)
|
||||
.map(p -> (nodeName() + " *--> " + p.nodeName()))
|
||||
.stream().toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean belongsToAny(final Set<String> groups) {
|
||||
return true; // we currently do not filter booking item types
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nodeName() {
|
||||
return "BI_" + name();
|
||||
|
@ -1,9 +1,11 @@
|
||||
package net.hostsharing.hsadminng.hs.booking.item;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public interface Node {
|
||||
|
||||
String nodeName();
|
||||
List<String> edges();
|
||||
boolean belongsToAny(Set<String> groups);
|
||||
List<String> edges(final Set<String> inGroup);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@ -18,7 +19,11 @@ import java.util.function.Function;
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.stream.Collectors.joining;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.*;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.assignedTo;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.optionalParent;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.optionallyAssignedTo;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.requiredParent;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.EntityTypeRelation.requires;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.OPTIONAL;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationPolicy.REQUIRED;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.RelationType.ASSIGNED_TO_ASSET;
|
||||
@ -106,11 +111,14 @@ public enum HsHostingAssetType implements Node {
|
||||
inGroup("MariaDB"),
|
||||
requiredParent(MARIADB_USER)), // thus, the MARIADB_USER:Agent becomes RBAC owner
|
||||
|
||||
IP_NUMBER(
|
||||
IPV4_NUMBER(
|
||||
inGroup("Server"),
|
||||
assignedTo(CLOUD_SERVER),
|
||||
assignedTo(MANAGED_SERVER),
|
||||
assignedTo(MANAGED_WEBSPACE)
|
||||
optionallyAssignedTo(CLOUD_SERVER).or(MANAGED_SERVER).or(MANAGED_WEBSPACE)
|
||||
),
|
||||
|
||||
IPV6_NUMBER(
|
||||
inGroup("Server"),
|
||||
optionallyAssignedTo(CLOUD_SERVER).or(MANAGED_SERVER).or(MANAGED_WEBSPACE)
|
||||
);
|
||||
|
||||
private final String groupName;
|
||||
@ -144,44 +152,50 @@ public enum HsHostingAssetType implements Node {
|
||||
.orElse(RelationPolicy.FORBIDDEN);
|
||||
}
|
||||
|
||||
public HsBookingItemType bookingItemType() {
|
||||
public Set<HsBookingItemType> bookingItemTypes() {
|
||||
return stream(relations)
|
||||
.filter(r -> r.relationType == BOOKING_ITEM)
|
||||
.map(r -> HsBookingItemType.valueOf(r.relatedType(this).toString()))
|
||||
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||
.orElse(null);
|
||||
.map(r -> r.relatedTypes(this))
|
||||
.stream().flatMap(Set::stream)
|
||||
.map(r -> (HsBookingItemType) r)
|
||||
.collect(toSet());
|
||||
}
|
||||
|
||||
public RelationPolicy parentAssetPolicy() {
|
||||
return stream(relations)
|
||||
.filter(r -> r.relationType == PARENT_ASSET)
|
||||
.map(r -> r.relationPolicy)
|
||||
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||
.map(r -> r.relationPolicy)
|
||||
.orElse(RelationPolicy.FORBIDDEN);
|
||||
}
|
||||
|
||||
public HsHostingAssetType parentAssetType() {
|
||||
public Set<HsHostingAssetType> parentAssetTypes() {
|
||||
return stream(relations)
|
||||
.filter(r -> r.relationType == PARENT_ASSET)
|
||||
.map(r -> HsHostingAssetType.valueOf(r.relatedType(this).toString()))
|
||||
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||
.orElse(null);
|
||||
.map(r -> r.relatedTypes(this))
|
||||
.stream().flatMap(Set::stream)
|
||||
.map(r -> (HsHostingAssetType) r)
|
||||
.collect(toSet());
|
||||
}
|
||||
|
||||
public RelationPolicy assignedToAssetPolicy() {
|
||||
return stream(relations)
|
||||
.filter(r -> r.relationType == ASSIGNED_TO_ASSET)
|
||||
.map(r -> r.relationPolicy)
|
||||
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||
.map(r -> r.relationPolicy)
|
||||
.orElse(RelationPolicy.FORBIDDEN);
|
||||
}
|
||||
|
||||
public HsHostingAssetType assignedToAssetType() {
|
||||
public Set<HsHostingAssetType> assignedToAssetTypes() {
|
||||
return stream(relations)
|
||||
.filter(r -> r.relationType == ASSIGNED_TO_ASSET)
|
||||
.map(r -> HsHostingAssetType.valueOf(r.relatedType(this).toString()))
|
||||
.reduce(HsHostingAssetType::onlyASingleElementExpectedException)
|
||||
.orElse(null);
|
||||
.map(r -> r.relatedTypes(this))
|
||||
.stream().flatMap(Set::stream)
|
||||
.map(r -> (HsHostingAssetType) r)
|
||||
.collect(toSet());
|
||||
}
|
||||
|
||||
private static <X> X onlyASingleElementExpectedException(Object a, Object b) {
|
||||
@ -189,12 +203,22 @@ public enum HsHostingAssetType implements Node {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> edges() {
|
||||
public List<String> edges(final Set<String> inGroups) {
|
||||
return stream(relations)
|
||||
.map(r -> nodeName() + r.edge + r.relatedType(this).nodeName())
|
||||
.map(r -> r.relatedTypes(this).stream()
|
||||
.filter(x -> x.belongsToAny(inGroups))
|
||||
.map(x -> nodeName() + r.edge + x.nodeName())
|
||||
.toList())
|
||||
.flatMap(List::stream)
|
||||
.sorted()
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean belongsToAny(final Set<String> groups) {
|
||||
return groups.contains(this.groupName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nodeName() {
|
||||
return "HA_" + name();
|
||||
@ -220,12 +244,12 @@ public enum HsHostingAssetType implements Node {
|
||||
.map(t -> "entity " + t.nodeName())
|
||||
.collect(joining("\n"));
|
||||
final String bookingItemEdges = stream(HsBookingItemType.values())
|
||||
.map(HsBookingItemType::edges)
|
||||
.map(t -> t.edges(includedHostingGroups))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(joining("\n"));
|
||||
final String hostingAssetEdges = stream(HsHostingAssetType.values())
|
||||
.filter(t -> t.isInGroups(includedHostingGroups))
|
||||
.map(HsHostingAssetType::edges)
|
||||
.filter(t -> t.isInGroups(includedHostingGroups))
|
||||
.map(t -> t.edges(includedHostingGroups))
|
||||
.flatMap(Collection::stream)
|
||||
.collect(joining("\n"));
|
||||
return """
|
||||
@ -239,7 +263,7 @@ public enum HsHostingAssetType implements Node {
|
||||
package Booking #feb28c {
|
||||
%{bookingNodes}
|
||||
}
|
||||
|
||||
|
||||
package Hosting #feb28c{
|
||||
%{hostingGroups}
|
||||
}
|
||||
@ -257,12 +281,12 @@ public enum HsHostingAssetType implements Node {
|
||||
Booking -down[hidden]->Legend
|
||||
```
|
||||
"""
|
||||
.replace("%{caption}", caption)
|
||||
.replace("%{bookingNodes}", bookingNodes)
|
||||
.replace("%{hostingGroups}", hostingGroups)
|
||||
.replace("%{hostingAssetNodeStyles}", hostingAssetNodes)
|
||||
.replace("%{bookingItemEdges}", bookingItemEdges)
|
||||
.replace("%{hostingAssetEdges}", hostingAssetEdges);
|
||||
.replace("%{caption}", caption)
|
||||
.replace("%{bookingNodes}", bookingNodes)
|
||||
.replace("%{hostingGroups}", hostingGroups)
|
||||
.replace("%{hostingAssetNodeStyles}", hostingAssetNodes)
|
||||
.replace("%{bookingItemEdges}", bookingItemEdges)
|
||||
.replace("%{hostingAssetEdges}", hostingAssetEdges);
|
||||
}
|
||||
|
||||
private boolean isInGroups(final Set<String> assetGroups) {
|
||||
@ -291,15 +315,17 @@ public enum HsHostingAssetType implements Node {
|
||||
.map(t -> t.groupName)
|
||||
.collect(toSet()));
|
||||
|
||||
markdown.append(renderAsPlantUML("Domain", Set.of("Domain", "Webspace", "Server")))
|
||||
.append(renderAsPlantUML("MariaDB", Set.of("MariaDB", "Webspace", "Server")))
|
||||
.append(renderAsPlantUML("PostgreSQL", Set.of("PostgreSQL", "Webspace", "Server")));
|
||||
markdown
|
||||
.append(renderAsPlantUML("Server+Webspace", Set.of("Server", "Webspace")))
|
||||
.append(renderAsPlantUML("Domain", Set.of("Domain", "Webspace")))
|
||||
.append(renderAsPlantUML("MariaDB", Set.of("MariaDB", "Webspace")))
|
||||
.append(renderAsPlantUML("PostgreSQL", Set.of("PostgreSQL", "Webspace")));
|
||||
|
||||
markdown.append("""
|
||||
|
||||
This code generated was by %{this}.main, do not amend manually.
|
||||
"""
|
||||
.replace("%{this}", HsHostingAssetType.class.getSimpleName()));
|
||||
.replace("%{this}", HsHostingAssetType.class.getSimpleName()));
|
||||
|
||||
return markdown.toString();
|
||||
}
|
||||
@ -317,8 +343,8 @@ public enum HsHostingAssetType implements Node {
|
||||
|
||||
public enum RelationType {
|
||||
BOOKING_ITEM,
|
||||
PARENT_ASSET,
|
||||
ASSIGNED_TO_ASSET
|
||||
PARENT_ASSET,
|
||||
ASSIGNED_TO_ASSET
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,27 +354,78 @@ class EntityTypeRelation<E, T extends Node> {
|
||||
final HsHostingAssetType.RelationPolicy relationPolicy;
|
||||
final HsHostingAssetType.RelationType relationType;
|
||||
final Function<HsHostingAssetEntity, E> getter;
|
||||
private final T relatedType;
|
||||
private final List<T> acceptedRelatedTypes;
|
||||
final String edge;
|
||||
|
||||
public T relatedType(final HsHostingAssetType referringType) {
|
||||
private EntityTypeRelation(
|
||||
final HsHostingAssetType.RelationPolicy relationPolicy,
|
||||
final HsHostingAssetType.RelationType relationType,
|
||||
final Function<HsHostingAssetEntity, E> getter,
|
||||
final T acceptedRelatedType,
|
||||
final String edge
|
||||
) {
|
||||
this(relationPolicy, relationType, getter, modifiyableListOf(acceptedRelatedType), edge);
|
||||
}
|
||||
|
||||
public <R extends Node> Set<R> relatedTypes(final HsHostingAssetType referringType) {
|
||||
final Set<Node> result = acceptedRelatedTypes.stream()
|
||||
.map(t -> t == HsHostingAssetType.SAME_TYPE ? referringType : t)
|
||||
.collect(toSet());
|
||||
//noinspection unchecked
|
||||
return relatedType == HsHostingAssetType.SAME_TYPE ? (T) referringType : relatedType;
|
||||
return (Set<R>) result;
|
||||
}
|
||||
|
||||
static EntityTypeRelation<HsBookingItemEntity, HsBookingItemType> requires(final HsBookingItemType bookingItemType) {
|
||||
return new EntityTypeRelation<>(REQUIRED, BOOKING_ITEM, HsHostingAssetEntity::getBookingItem, bookingItemType, " *==> ");
|
||||
return new EntityTypeRelation<>(
|
||||
REQUIRED,
|
||||
BOOKING_ITEM,
|
||||
HsHostingAssetEntity::getBookingItem,
|
||||
bookingItemType,
|
||||
" *==> ");
|
||||
}
|
||||
|
||||
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> optionalParent(final HsHostingAssetType hostingAssetType) {
|
||||
return new EntityTypeRelation<>(OPTIONAL, PARENT_ASSET, HsHostingAssetEntity::getParentAsset, hostingAssetType, " o..> ");
|
||||
return new EntityTypeRelation<>(
|
||||
OPTIONAL,
|
||||
PARENT_ASSET,
|
||||
HsHostingAssetEntity::getParentAsset,
|
||||
hostingAssetType,
|
||||
" o..> ");
|
||||
}
|
||||
|
||||
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> requiredParent(final HsHostingAssetType hostingAssetType) {
|
||||
return new EntityTypeRelation<>(REQUIRED, PARENT_ASSET, HsHostingAssetEntity::getParentAsset, hostingAssetType, " *==> ");
|
||||
return new EntityTypeRelation<>(
|
||||
REQUIRED,
|
||||
PARENT_ASSET,
|
||||
HsHostingAssetEntity::getParentAsset,
|
||||
hostingAssetType,
|
||||
" *==> ");
|
||||
}
|
||||
|
||||
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> assignedTo(final HsHostingAssetType hostingAssetType) {
|
||||
return new EntityTypeRelation<>(REQUIRED, ASSIGNED_TO_ASSET, HsHostingAssetEntity::getAssignedToAsset, hostingAssetType, " o..> ");
|
||||
return new EntityTypeRelation<>(
|
||||
REQUIRED,
|
||||
ASSIGNED_TO_ASSET,
|
||||
HsHostingAssetEntity::getAssignedToAsset,
|
||||
hostingAssetType,
|
||||
" o--> ");
|
||||
}
|
||||
|
||||
EntityTypeRelation<E, T> or(final T alternativeHostingAssetType) {
|
||||
acceptedRelatedTypes.add(alternativeHostingAssetType);
|
||||
return this;
|
||||
}
|
||||
|
||||
static EntityTypeRelation<HsHostingAssetEntity, HsHostingAssetType> optionallyAssignedTo(final HsHostingAssetType hostingAssetType) {
|
||||
return new EntityTypeRelation<>(
|
||||
OPTIONAL,
|
||||
ASSIGNED_TO_ASSET,
|
||||
HsHostingAssetEntity::getAssignedToAsset,
|
||||
hostingAssetType,
|
||||
" o..> ");
|
||||
}
|
||||
|
||||
private static <T extends Node> ArrayList<T> modifiyableListOf(final T acceptedRelatedType) {
|
||||
return new ArrayList<>(List.of(acceptedRelatedType));
|
||||
}
|
||||
}
|
||||
|
@ -12,9 +12,11 @@ import net.hostsharing.hsadminng.hs.validation.ValidatableProperty;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
@ -37,17 +39,17 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
super(properties);
|
||||
this.bookingItemReferenceValidation = new ReferenceValidator<>(
|
||||
assetType.bookingItemPolicy(),
|
||||
assetType.bookingItemType(),
|
||||
assetType.bookingItemTypes(),
|
||||
HsHostingAssetEntity::getBookingItem,
|
||||
HsBookingItemEntity::getType);
|
||||
this.parentAssetReferenceValidation = new ReferenceValidator<>(
|
||||
assetType.parentAssetPolicy(),
|
||||
assetType.parentAssetType(),
|
||||
assetType.parentAssetTypes(),
|
||||
HsHostingAssetEntity::getParentAsset,
|
||||
HsHostingAssetEntity::getType);
|
||||
this.assignedToAssetReferenceValidation = new ReferenceValidator<>(
|
||||
assetType.assignedToAssetPolicy(),
|
||||
assetType.assignedToAssetType(),
|
||||
assetType.assignedToAssetTypes(),
|
||||
HsHostingAssetEntity::getAssignedToAsset,
|
||||
HsHostingAssetEntity::getType);
|
||||
this.alarmContactValidation = alarmContactValidation;
|
||||
@ -154,17 +156,17 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
static class ReferenceValidator<S, T> {
|
||||
|
||||
private final HsHostingAssetType.RelationPolicy policy;
|
||||
private final T referencedEntityType;
|
||||
private final Set<T> referencedEntityTypes;
|
||||
private final Function<HsHostingAssetEntity, S> referencedEntityGetter;
|
||||
private final Function<S, T> referencedEntityTypeGetter;
|
||||
|
||||
public ReferenceValidator(
|
||||
final HsHostingAssetType.RelationPolicy policy,
|
||||
final T subEntityType,
|
||||
final Set<T> referencedEntityTypes,
|
||||
final Function<HsHostingAssetEntity, S> referencedEntityGetter,
|
||||
final Function<S, T> referencedEntityTypeGetter) {
|
||||
this.policy = policy;
|
||||
this.referencedEntityType = subEntityType;
|
||||
this.referencedEntityTypes = referencedEntityTypes;
|
||||
this.referencedEntityGetter = referencedEntityGetter;
|
||||
this.referencedEntityTypeGetter = referencedEntityTypeGetter;
|
||||
}
|
||||
@ -173,7 +175,7 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
final HsHostingAssetType.RelationPolicy policy,
|
||||
final Function<HsHostingAssetEntity, S> referencedEntityGetter) {
|
||||
this.policy = policy;
|
||||
this.referencedEntityType = null;
|
||||
this.referencedEntityTypes = Set.of();
|
||||
this.referencedEntityGetter = referencedEntityGetter;
|
||||
this.referencedEntityTypeGetter = e -> null;
|
||||
}
|
||||
@ -185,15 +187,15 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
|
||||
switch (policy) {
|
||||
case REQUIRED:
|
||||
if (actualEntityType != referencedEntityType) {
|
||||
if (!referencedEntityTypes.contains(actualEntityType)) {
|
||||
return List.of(actualEntityType == null
|
||||
? referenceFieldName + "' must be of type " + referencedEntityType + " but is null"
|
||||
: referenceFieldName + "' must be of type " + referencedEntityType + " but is of type " + actualEntityType);
|
||||
? referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is null"
|
||||
: referenceFieldName + "' must be of type " + toDisplay(referencedEntityTypes) + " but is of type " + actualEntityType);
|
||||
}
|
||||
break;
|
||||
case OPTIONAL:
|
||||
if (actualEntityType != null && actualEntityType != referencedEntityType) {
|
||||
return List.of(referenceFieldName + "' must be null or of type " + referencedEntityType + " but is of type "
|
||||
if (actualEntityType != null && !referencedEntityTypes.contains(actualEntityType)) {
|
||||
return List.of(referenceFieldName + "' must be null or of type " + toDisplay(referencedEntityTypes) + " but is of type "
|
||||
+ actualEntityType);
|
||||
}
|
||||
break;
|
||||
@ -205,6 +207,10 @@ public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHo
|
||||
}
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
private String toDisplay(final Set<T> referencedEntityTypes) {
|
||||
return referencedEntityTypes.stream().sorted().map(Object::toString).collect(Collectors.joining(" or "));
|
||||
}
|
||||
}
|
||||
|
||||
static class AlarmContact extends ReferenceValidator<HsOfficeContactEntity, Enum<?>> {
|
||||
|
@ -32,6 +32,8 @@ public class HostingAssetEntityValidatorRegistry {
|
||||
register(PGSQL_INSTANCE, new HsPostgreSqlDbInstanceHostingAssetValidator());
|
||||
register(PGSQL_USER, new HsPostgreSqlUserHostingAssetValidator());
|
||||
register(PGSQL_DATABASE, new HsPostgreSqlDatabaseHostingAssetValidator());
|
||||
register(IPV4_NUMBER, new HsIPv4NumberHostingAssetValidator());
|
||||
register(IPV6_NUMBER, new HsIPv6NumberHostingAssetValidator());
|
||||
}
|
||||
|
||||
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {
|
||||
|
@ -0,0 +1,26 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV4_NUMBER;
|
||||
|
||||
class HsIPv4NumberHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
private static final Pattern IPV4_REGEX = Pattern.compile("^((25[0-5]|(2[0-4]|1\\d|[1-9]|)\\d)\\.?\\b){4}$");
|
||||
|
||||
HsIPv4NumberHostingAssetValidator() {
|
||||
super(
|
||||
IPV4_NUMBER,
|
||||
AlarmContact.isOptional(),
|
||||
|
||||
NO_EXTRA_PROPERTIES
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||
return IPV4_REGEX;
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.IPV6_NUMBER;
|
||||
|
||||
class HsIPv6NumberHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
// simplified pattern, the real check is done by letting Java parse the address
|
||||
private static final Pattern IPV6_REGEX = Pattern.compile("([a-f0-9:]+:+)+[a-f0-9]+");
|
||||
|
||||
HsIPv6NumberHostingAssetValidator() {
|
||||
super(
|
||||
IPV6_NUMBER,
|
||||
AlarmContact.isOptional(),
|
||||
|
||||
NO_EXTRA_PROPERTIES
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> validateEntity(final HsHostingAssetEntity assetEntity) {
|
||||
final var violations = super.validateEntity(assetEntity);
|
||||
|
||||
if (!isValidIPv6Address(assetEntity.getIdentifier())) {
|
||||
violations.add("'identifier' expected to be a valid IPv6 address, but is '" + assetEntity.getIdentifier() + "'");
|
||||
}
|
||||
|
||||
return violations;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
|
||||
return IPV6_REGEX;
|
||||
}
|
||||
|
||||
private boolean isValidIPv6Address(final String identifier) {
|
||||
try {
|
||||
return InetAddress.getByName(identifier) instanceof java.net.Inet6Address;
|
||||
} catch (UnknownHostException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package net.hostsharing.hsadminng.mapper;
|
||||
|
||||
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -51,6 +52,11 @@ public class Array {
|
||||
return of();
|
||||
}
|
||||
|
||||
public static <T> T[] emptyArray(final Class<T> elementClass) {
|
||||
//noinspection unchecked
|
||||
return (T[]) java.lang.reflect.Array.newInstance(elementClass, 0);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <T> T[] insertNewEntriesAfterExistingEntry(final T[] array, final T entryToFind, final T... newEntries) {
|
||||
final var arrayList = new ArrayList<>(asList(array));
|
||||
|
Reference in New Issue
Block a user