From dbf83dd0da532fe783d8480fe6686a49b48a0db0 Mon Sep 17 00:00:00 2001 From: copierrj Date: Tue, 9 Jun 2015 16:35:45 +0200 Subject: [PATCH] unique name validation moved to service --- .../domain/query/ValidateUniqueName.java | 25 ++ .../response/UniqueNameValidationResult.java | 45 ++++ .../domain/response/ValidationResult.java | 8 + .../nl/idgis/publisher/admin/LayerAdmin.java | 31 ++- publisher-web/app/controllers/Groups.java | 168 +++++++------- publisher-web/app/controllers/Layers.java | 182 +++++++-------- publisher-web/app/controllers/Services.java | 213 +++++++++--------- 7 files changed, 399 insertions(+), 273 deletions(-) create mode 100644 publisher-domain/src/main/java/nl/idgis/publisher/domain/query/ValidateUniqueName.java create mode 100644 publisher-domain/src/main/java/nl/idgis/publisher/domain/response/UniqueNameValidationResult.java create mode 100644 publisher-domain/src/main/java/nl/idgis/publisher/domain/response/ValidationResult.java diff --git a/publisher-domain/src/main/java/nl/idgis/publisher/domain/query/ValidateUniqueName.java b/publisher-domain/src/main/java/nl/idgis/publisher/domain/query/ValidateUniqueName.java new file mode 100644 index 000000000..9fc094447 --- /dev/null +++ b/publisher-domain/src/main/java/nl/idgis/publisher/domain/query/ValidateUniqueName.java @@ -0,0 +1,25 @@ +package nl.idgis.publisher.domain.query; + +import java.util.Objects; + +import nl.idgis.publisher.domain.response.UniqueNameValidationResult; + +public class ValidateUniqueName implements DomainQuery { + + private static final long serialVersionUID = -8948822157181419535L; + + private final String name; + + public ValidateUniqueName(String name) { + this.name = Objects.requireNonNull(name); + } + + public String name() { + return name; + } + + @Override + public String toString() { + return "ValidateUniqueName [name=" + name + "]"; + } +} diff --git a/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/UniqueNameValidationResult.java b/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/UniqueNameValidationResult.java new file mode 100644 index 000000000..3a965796e --- /dev/null +++ b/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/UniqueNameValidationResult.java @@ -0,0 +1,45 @@ +package nl.idgis.publisher.domain.response; + +import java.util.Objects; + +public class UniqueNameValidationResult implements ValidationResult { + + private static final long serialVersionUID = -3800481429856190153L; + + public enum ConflictType { + LAYER, + LAYERGROUP, + SERVICE + } + + private final ConflictType conflictType; + + private UniqueNameValidationResult(ConflictType conflictType) { + this.conflictType = conflictType; + } + + public static UniqueNameValidationResult valid() { + return new UniqueNameValidationResult(null); + } + + public static UniqueNameValidationResult conflict(ConflictType conflictType) { + return new UniqueNameValidationResult(Objects.requireNonNull(conflictType, "conflict type missing")); + } + + public boolean isValid() { + return conflictType == null; + } + + public ConflictType conflictType() { + if(conflictType == null) { + throw new IllegalStateException("no conflict"); + } + + return conflictType; + } + + @Override + public String toString() { + return "UniqueNameValidationResult [conflictType=" + conflictType + "]"; + } +} diff --git a/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/ValidationResult.java b/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/ValidationResult.java new file mode 100644 index 000000000..416473302 --- /dev/null +++ b/publisher-domain/src/main/java/nl/idgis/publisher/domain/response/ValidationResult.java @@ -0,0 +1,8 @@ +package nl.idgis.publisher.domain.response; + +import java.io.Serializable; + +public interface ValidationResult extends Serializable { + + boolean isValid(); +} diff --git a/publisher-service/src/main/java/nl/idgis/publisher/admin/LayerAdmin.java b/publisher-service/src/main/java/nl/idgis/publisher/admin/LayerAdmin.java index 3577127f9..5658e528f 100644 --- a/publisher-service/src/main/java/nl/idgis/publisher/admin/LayerAdmin.java +++ b/publisher-service/src/main/java/nl/idgis/publisher/admin/LayerAdmin.java @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import nl.idgis.publisher.database.AsyncSQLQuery; + import nl.idgis.publisher.domain.query.GetLayerParentGroups; import nl.idgis.publisher.domain.query.GetLayerParentServices; import nl.idgis.publisher.domain.query.ListLayerKeywords; @@ -30,8 +31,10 @@ import nl.idgis.publisher.domain.query.ListLayers; import nl.idgis.publisher.domain.query.PutLayerKeywords; import nl.idgis.publisher.domain.query.PutLayerStyles; +import nl.idgis.publisher.domain.query.ValidateUniqueName; import nl.idgis.publisher.domain.response.Page; import nl.idgis.publisher.domain.response.Response; +import nl.idgis.publisher.domain.response.UniqueNameValidationResult; import nl.idgis.publisher.domain.service.CrudOperation; import nl.idgis.publisher.domain.service.CrudResponse; import nl.idgis.publisher.domain.web.Layer; @@ -40,8 +43,9 @@ import nl.idgis.publisher.domain.web.Service; import nl.idgis.publisher.domain.web.Style; import nl.idgis.publisher.domain.web.TiledLayer; -import nl.idgis.publisher.utils.StreamUtils; + import nl.idgis.publisher.utils.TypedList; + import akka.actor.ActorRef; import akka.actor.Props; @@ -49,7 +53,6 @@ import com.mysema.query.sql.SQLSubQuery; import com.mysema.query.types.ConstantImpl; import com.mysema.query.types.Expression; -import com.mysema.query.types.Path; import com.mysema.query.types.expr.DslExpression; import com.mysema.query.types.path.PathBuilder; @@ -82,6 +85,30 @@ protected void preStartAdmin() { doQuery (GetLayerParentGroups.class, this::handleGetLayerParentGroups); doQuery (GetLayerParentServices.class, this::handleGetLayerParentServices); + + doQuery(ValidateUniqueName.class, this::handleValidateUniqueName); + } + + private CompletableFuture handleValidateUniqueName(ValidateUniqueName validateUniqueName) { + return db.query() + .from(genericLayer) + .leftJoin(leafLayer).on(leafLayer.genericLayerId.eq(genericLayer.id)) + .leftJoin(service).on(service.genericLayerId.eq(genericLayer.id)) + .where(genericLayer.name.eq(validateUniqueName.name())) + .singleResult(leafLayer.id, service.id).thenApply(optionalResult -> + optionalResult + .map(result -> { + if(result.get(leafLayer.id) != null) { + return UniqueNameValidationResult.conflict(UniqueNameValidationResult.ConflictType.LAYER); + } + + if(result.get(service.id) != null) { + return UniqueNameValidationResult.conflict(UniqueNameValidationResult.ConflictType.SERVICE); + } + + return UniqueNameValidationResult.conflict(UniqueNameValidationResult.ConflictType.LAYERGROUP); + }) + .orElse(UniqueNameValidationResult.valid())); } private CompletableFuture> handleListLayers () { diff --git a/publisher-web/app/controllers/Groups.java b/publisher-web/app/controllers/Groups.java index 140aadd7b..4dc75fc39 100644 --- a/publisher-web/app/controllers/Groups.java +++ b/publisher-web/app/controllers/Groups.java @@ -8,11 +8,13 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import scala.runtime.AbstractFunction1; + import models.Domain; import models.Domain.Function; import models.Domain.Function2; import models.Domain.Function3; import models.Domain.Function5; + import nl.idgis.publisher.domain.query.GetGroupParentGroups; import nl.idgis.publisher.domain.query.GetGroupParentServices; import nl.idgis.publisher.domain.query.GetGroupStructure; @@ -21,6 +23,7 @@ import nl.idgis.publisher.domain.query.ListLayerGroups; import nl.idgis.publisher.domain.query.ListLayers; import nl.idgis.publisher.domain.query.PutGroupStructure; +import nl.idgis.publisher.domain.query.ValidateUniqueName; import nl.idgis.publisher.domain.response.Page; import nl.idgis.publisher.domain.response.Response; import nl.idgis.publisher.domain.service.CrudOperation; @@ -29,6 +32,7 @@ import nl.idgis.publisher.domain.web.LayerGroup; import nl.idgis.publisher.domain.web.Service; import nl.idgis.publisher.domain.web.tree.GroupLayer; + import play.Logger; import play.Play; import play.api.mvc.Call; @@ -46,6 +50,7 @@ import views.html.layers.layerPagerFooter; import views.html.layers.layerPagerHeader; import actions.DefaultAuthenticator; + import akka.actor.ActorSelection; @Security.Authenticated (DefaultAuthenticator.class) @@ -68,97 +73,100 @@ public Result apply (final Page groups, final Page layers) th } - public static Promise submitCreateUpdate () { - final ActorSelection database = Akka.system().actorSelection (databaseRef); + private static Promise performCreateUpdate(final ActorSelection database, final Form form) { + if (form.field("structure").value() == null){ + form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); + } + + if (form.hasErrors ()) { + return renderCreateForm (form); + } + // validation end + + final GroupForm groupForm = form.get (); + final List layerIds = (groupForm.structure == null)?(new ArrayList()):(groupForm.structure); + Logger.debug ("Group structure list: " + layerIds); + + final List layerStyleIds = groupForm.styles == null ? new ArrayList<>() : groupForm.styles; + Logger.debug ("Group layer style list: " + layerStyleIds); + + final LayerGroup group = new LayerGroup(groupForm.id, groupForm.name.trim (), groupForm.title, + groupForm.abstractText,(groupForm.enabled ? groupForm.getTiledLayer() : null), false); return from (database) - .list (LayerGroup.class) - .list (Layer.class) - .list (Service.class) - .executeFlat (new Function3, Page, Page, Promise> () { - + .put(group) + .executeFlat (new Function, Promise> () { @Override - public Promise apply (final Page groups, final Page layers, final Page services) throws Throwable { - final Form form = Form.form (GroupForm.class).bindFromRequest (); - Logger.debug ("submit Group: " + form.field("name").value()); - - // validation start - if (form.field("id").value().equals(ID)){ - for (LayerGroup layerGroup : groups.values()) { - if (form.field("name").value().trim ().equals(layerGroup.name())){ - form.reject("name", Domain.message("web.application.page.groups.form.field.name.validation.groupexists.error")); - } - } - for (Layer layer : layers.values()) { - if (form.field("name").value().trim ().equals(layer.name())){ - form.reject("name", Domain.message("web.application.page.groups.form.field.name.validation.layerexists.error")); - } - } - for (final Service service: services.values ()) { - if (form.field ("name").value ().trim ().equals (service.name ())) { - form.reject ("name", Domain.message("web.application.page.groups.form.field.name.validation.serviceexists.error")); - } - } - } - if (form.field("structure").value() == null){ - form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); - } - - if (form.hasErrors ()) { - return renderCreateForm (form); - } - // validation end - - final GroupForm groupForm = form.get (); - final List layerIds = (groupForm.structure == null)?(new ArrayList()):(groupForm.structure); - Logger.debug ("Group structure list: " + layerIds); - - final List layerStyleIds = groupForm.styles == null ? new ArrayList<>() : groupForm.styles; - Logger.debug ("Group layer style list: " + layerStyleIds); - - final LayerGroup group = new LayerGroup(groupForm.id, groupForm.name.trim (), groupForm.title, - groupForm.abstractText,(groupForm.enabled ? groupForm.getTiledLayer() : null), false); - + public Promise apply (final Response response) throws Throwable { + // Get the id of the layer we just put + String groupId = response.getValue().toString(); + PutGroupStructure putGroupStructure = new PutGroupStructure (groupId, layerIds, layerStyleIds); return from (database) - .put(group) + .query(putGroupStructure) .executeFlat (new Function, Promise> () { @Override public Promise apply (final Response response) throws Throwable { - // Get the id of the layer we just put - String groupId = response.getValue().toString(); - PutGroupStructure putGroupStructure = new PutGroupStructure (groupId, layerIds, layerStyleIds); - return from (database) - .query(putGroupStructure) - .executeFlat (new Function, Promise> () { - @Override - public Promise apply (final Response response) throws Throwable { - if (CrudOperation.CREATE.equals (response.getOperation())) { - Logger.debug ("Created group " + group); - if (response.getOperationResponse().equals(CrudResponse.NOK)){ - flash("danger", Domain.message("web.application.page.groups.form.field.structure.validation.cycle", response.getValue().toString())); - form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); - return Promise.pure (redirect (routes.Groups.edit(groupId))); - } else { - flash ("success", Domain.message("web.application.page.groups.name") + " " + groupForm.getName () + " is " + Domain.message("web.application.added").toLowerCase()); - } - }else{ - Logger.debug ("Updated group " + group); - if (response.getOperationResponse().equals(CrudResponse.NOK)){ - flash("danger", Domain.message("web.application.page.groups.form.field.structure.validation.cycle", response.getValue().toString())); - form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); - return Promise.pure (redirect (routes.Groups.edit(groupId))); - } else { - flash ("success", Domain.message("web.application.page.groups.name") + " " + groupForm.getName () + " is " + Domain.message("web.application.updated").toLowerCase()); - } - } - return Promise.pure (redirect (routes.Groups.list (null, 1))); - } - }); + if (CrudOperation.CREATE.equals (response.getOperation())) { + Logger.debug ("Created group " + group); + if (response.getOperationResponse().equals(CrudResponse.NOK)){ + flash("danger", Domain.message("web.application.page.groups.form.field.structure.validation.cycle", response.getValue().toString())); + form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); + return Promise.pure (redirect (routes.Groups.edit(groupId))); + } else { + flash ("success", Domain.message("web.application.page.groups.name") + " " + groupForm.getName () + " is " + Domain.message("web.application.added").toLowerCase()); + } + }else{ + Logger.debug ("Updated group " + group); + if (response.getOperationResponse().equals(CrudResponse.NOK)){ + flash("danger", Domain.message("web.application.page.groups.form.field.structure.validation.cycle", response.getValue().toString())); + form.reject("structure", Domain.message("web.application.page.groups.form.field.structure.validation.error")); + return Promise.pure (redirect (routes.Groups.edit(groupId))); + } else { + flash ("success", Domain.message("web.application.page.groups.name") + " " + groupForm.getName () + " is " + Domain.message("web.application.updated").toLowerCase()); + } + } + return Promise.pure (redirect (routes.Groups.list (null, 1))); } }); + } + }); + } + + public static Promise submitCreateUpdate () { + final ActorSelection database = Akka.system().actorSelection (databaseRef); + + final Form form = Form.form (GroupForm.class).bindFromRequest (); + final String name = form.field ("name").valueOr (null); + + if (name == null) { + return performCreateUpdate(database, form); + } else { + return from (database) + .query (new ValidateUniqueName (name)) + .executeFlat (validationResult -> { + if(validationResult.isValid ()) { + Logger.debug("name is valid: " + name); + } else { + Logger.debug("name is already in use: " + name); + + switch(validationResult.conflictType ()) { + case LAYER: + form.reject ("name", "web.application.page.groups.form.field.name.validation.layerexists.error"); + break; + case LAYERGROUP: + form.reject ("name", "web.application.page.groups.form.field.name.validation.groupexists.error"); + break; + case SERVICE: + form.reject ("name", "web.application.page.groups.form.field.name.validation.serviceexists.error"); + break; + default: + break; + } } + + return performCreateUpdate (database, form); }); - + } } public static Promise list (final String query, final long page) { diff --git a/publisher-web/app/controllers/Layers.java b/publisher-web/app/controllers/Layers.java index 74dc9e48f..cbbc5b23c 100644 --- a/publisher-web/app/controllers/Layers.java +++ b/publisher-web/app/controllers/Layers.java @@ -4,24 +4,21 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; import models.Domain; import models.Domain.Function; import models.Domain.Function2; -import models.Domain.Function3; -import models.Domain.Function4; import models.Domain.Function5; + import nl.idgis.publisher.domain.query.GetLayerParentGroups; import nl.idgis.publisher.domain.query.GetLayerParentServices; import nl.idgis.publisher.domain.query.GetLayerRef; import nl.idgis.publisher.domain.query.GetLayerServices; -import nl.idgis.publisher.domain.query.ListLayerKeywords; -import nl.idgis.publisher.domain.query.ListLayerStyles; import nl.idgis.publisher.domain.query.ListLayers; import nl.idgis.publisher.domain.query.ListStyles; import nl.idgis.publisher.domain.query.PutLayerKeywords; import nl.idgis.publisher.domain.query.PutLayerStyles; +import nl.idgis.publisher.domain.query.ValidateUniqueName; import nl.idgis.publisher.domain.response.Page; import nl.idgis.publisher.domain.response.Response; import nl.idgis.publisher.domain.service.CrudOperation; @@ -30,7 +27,7 @@ import nl.idgis.publisher.domain.web.LayerGroup; import nl.idgis.publisher.domain.web.Service; import nl.idgis.publisher.domain.web.Style; -import nl.idgis.publisher.domain.web.TiledLayer; + import play.Logger; import play.Play; import play.api.mvc.Call; @@ -48,6 +45,7 @@ import views.html.layers.layerPagerBody; import views.html.layers.layerPagerFooter; import actions.DefaultAuthenticator; + import akka.actor.ActorSelection; import com.fasterxml.jackson.databind.JsonNode; @@ -74,98 +72,106 @@ public Result apply (final Page