From 2545cbeada0ff90edf780976195c9c5708eb0e50 Mon Sep 17 00:00:00 2001 From: Cleverson Sacramento Date: Tue, 3 Jun 2014 11:36:25 -0300 Subject: [PATCH] Implementação do tratamento de erros de validação --- archetype/html-rest/src/main/resources/archetype-resources/src/main/java/rest/BookmarkREST.java | 29 +++++++++++------------------ impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/interceptor/RequiredPermissionInterceptor.java | 2 +- impl/core/src/main/java/br/gov/frameworkdemoiselle/security/RequiredPermissionInterceptor.java | 12 ++++++------ impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/Validate.java | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/ValidateInterceptor.java | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/PreconditionFailedException.java | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConstraintViolationExceptionMapper.java | 79 +++++++++++++++++++++++++++++-------------------------------------------------- impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/PreconditionFailedExceptionMapper.java | 16 ++++++++++++++++ 8 files changed, 293 insertions(+), 75 deletions(-) create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/Validate.java create mode 100644 impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/ValidateInterceptor.java create mode 100644 impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/PreconditionFailedException.java create mode 100644 impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/PreconditionFailedExceptionMapper.java diff --git a/archetype/html-rest/src/main/resources/archetype-resources/src/main/java/rest/BookmarkREST.java b/archetype/html-rest/src/main/resources/archetype-resources/src/main/java/rest/BookmarkREST.java index 1434639..664f612 100644 --- a/archetype/html-rest/src/main/resources/archetype-resources/src/main/java/rest/BookmarkREST.java +++ b/archetype/html-rest/src/main/resources/archetype-resources/src/main/java/rest/BookmarkREST.java @@ -37,7 +37,7 @@ public class BookmarkREST { @GET @Path("{id}") @Produces("application/json") - public Bookmark load(@PathParam("id") Long id) throws Exception { + public Bookmark load(@PathParam("id") Long id) { Bookmark result = bc.load(id); if (result == null) { @@ -52,9 +52,7 @@ public class BookmarkREST { @Produces("text/plain") @Consumes("application/json") public Response insert(Bookmark entity, @Context UriInfo uriInfo) { - if (entity.getId() != null) { - throw new BadRequestException(); - } + checkId(entity); String id = bc.insert(entity).getId().toString(); URI location = uriInfo.getRequestUriBuilder().path(id).build(); @@ -67,29 +65,24 @@ public class BookmarkREST { @Transactional @Consumes("application/json") public void update(@PathParam("id") Long id, Bookmark entity) { - if (entity.getId() != null) { - throw new BadRequestException(); - } - - if (bc.load(id) == null) { - throw new NotFoundException(); - } + checkId(entity); + load(id); entity.setId(id); bc.update(entity); } - - @DELETE - @Transactional - @Consumes("application/json") - public void delete(List ids) { - bc.delete(ids); - } @DELETE @Path("{id}") @Transactional public void delete(@PathParam("id") Long id) { + load(id); bc.delete(id); } + + private void checkId(Bookmark entity) throws BadRequestException { + if (entity.getId() != null) { + throw new BadRequestException(); + } + } } diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/interceptor/RequiredPermissionInterceptor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/interceptor/RequiredPermissionInterceptor.java index 05e3106..5662284 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/interceptor/RequiredPermissionInterceptor.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/internal/interceptor/RequiredPermissionInterceptor.java @@ -46,7 +46,7 @@ import org.slf4j.Logger; import br.gov.frameworkdemoiselle.security.RequiredPermission; /** - * Intercepts calls with {@code @RequiredPermission} annotations. + * Intercepts calls with {@code @Validate} annotations. * * @author SERPRO */ diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/security/RequiredPermissionInterceptor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/security/RequiredPermissionInterceptor.java index 2ba6e76..1d972c4 100644 --- a/impl/core/src/main/java/br/gov/frameworkdemoiselle/security/RequiredPermissionInterceptor.java +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/security/RequiredPermissionInterceptor.java @@ -51,7 +51,7 @@ import br.gov.frameworkdemoiselle.util.ResourceBundle; import br.gov.frameworkdemoiselle.util.Strings; /** - * Intercepts calls with {@code @RequiredPermission} annotations. + * Intercepts calls with {@code @Validate} annotations. * * @author SERPRO */ @@ -66,7 +66,7 @@ public class RequiredPermissionInterceptor implements Serializable { private static transient Logger logger; /** - * Gets the values for both resource and operation properties of {@code @RequiredPermission}. Delegates to + * Gets the values for both resource and operation properties of {@code @Validate}. Delegates to * {@code SecurityContext} check permissions. If the user has the required permission it executes the mehtod, * otherwise throws an exception. Returns what is returned from the intercepted method. If the method's return type * is {@code void} returns {@code null}. @@ -99,12 +99,12 @@ public class RequiredPermissionInterceptor implements Serializable { } /** - * Returns the resource defined in {@code @RequiredPermission} annotation, the name defined in {@code @AmbiguousQualifier} + * Returns the resource defined in {@code @Validate} annotation, the name defined in {@code @AmbiguousQualifier} * annotation or the class name itself * * @param ic * the {@code InvocationContext} in which the method is being called - * @return the resource defined in {@code @RequiredPermission} annotation, the name defined in {@code @AmbiguousQualifier} + * @return the resource defined in {@code @Validate} annotation, the name defined in {@code @AmbiguousQualifier} * annotation or the class name itself */ private String getResource(InvocationContext ic) { @@ -127,12 +127,12 @@ public class RequiredPermissionInterceptor implements Serializable { } /** - * Returns the operation defined in {@code @RequiredPermission} annotation, the name defined in {@code @AmbiguousQualifier} + * Returns the operation defined in {@code @Validate} annotation, the name defined in {@code @AmbiguousQualifier} * annotation or the method's name itself * * @param ic * the {@code InvocationContext} in which the method is being called - * @return the operation defined in {@code @RequiredPermission} annotation, the name defined in {@code @AmbiguousQualifier} + * @return the operation defined in {@code @Validate} annotation, the name defined in {@code @AmbiguousQualifier} * annotation or the method's name itself */ private String getOperation(InvocationContext ic) { diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/Validate.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/Validate.java new file mode 100644 index 0000000..0627ac8 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/Validate.java @@ -0,0 +1,55 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.validation; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import javax.interceptor.InterceptorBinding; + +@Inherited +@InterceptorBinding +@Target({ METHOD, TYPE }) +@Retention(RUNTIME) +public @interface Validate { + +} diff --git a/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/ValidateInterceptor.java b/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/ValidateInterceptor.java new file mode 100644 index 0000000..01bc424 --- /dev/null +++ b/impl/core/src/main/java/br/gov/frameworkdemoiselle/validation/ValidateInterceptor.java @@ -0,0 +1,80 @@ +/* + * Demoiselle Framework + * Copyright (C) 2010 SERPRO + * ---------------------------------------------------------------------------- + * This file is part of Demoiselle Framework. + * + * Demoiselle Framework is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License version 3 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License version 3 + * along with this program; if not, see + * or write to the Free Software Foundation, Inc., 51 Franklin Street, + * Fifth Floor, Boston, MA 02110-1301, USA. + * ---------------------------------------------------------------------------- + * Este arquivo é parte do Framework Demoiselle. + * + * O Framework Demoiselle é um software livre; você pode redistribuí-lo e/ou + * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação + * do Software Livre (FSF). + * + * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA + * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou + * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português + * para maiores detalhes. + * + * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título + * "LICENCA.txt", junto com esse programa. Se não, acesse + * ou escreva para a Fundação do Software Livre (FSF) Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA. + */ +package br.gov.frameworkdemoiselle.validation; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Set; + +import javax.interceptor.AroundInvoke; +import javax.interceptor.Interceptor; +import javax.interceptor.InvocationContext; +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.validation.Validation; +import javax.validation.Validator; +import javax.validation.ValidatorFactory; + +/** + * Intercepts calls with {@code @Validate} annotations. + * + * @author SERPRO + */ +@Validate +@Interceptor +public class ValidateInterceptor implements Serializable { + + private static final long serialVersionUID = 1L; + + @AroundInvoke + public Object manage(final InvocationContext ic) throws Exception { + Set> violations = new HashSet>(); + + for (Object params : ic.getParameters()) { + ValidatorFactory dfv = Validation.buildDefaultValidatorFactory(); + Validator validator = dfv.getValidator(); + + violations.addAll(validator.validate(params)); + } + + if (!violations.isEmpty()) { + throw new ConstraintViolationException(violations); + } + + return ic.proceed(); + } +} diff --git a/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/PreconditionFailedException.java b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/PreconditionFailedException.java new file mode 100644 index 0000000..c1dc560 --- /dev/null +++ b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/PreconditionFailedException.java @@ -0,0 +1,95 @@ +package br.gov.frameworkdemoiselle; + +import static javax.servlet.http.HttpServletResponse.SC_PRECONDITION_FAILED; + +import java.util.HashSet; +import java.util.Set; + +import javax.xml.ws.http.HTTPException; + +public class PreconditionFailedException extends HTTPException { + + private static final long serialVersionUID = 1L; + + private Set violations = new HashSet(); + + public PreconditionFailedException() { + super(SC_PRECONDITION_FAILED); + } + + public PreconditionFailedException addViolation(String property, String message) { + this.violations.add(new Violation(property, message)); + return this; + } + + public Set getViolations() { + return violations; + } + + public static class Violation { + + public String property; + + public String message; + + public Violation() { + } + + public Violation(String property, String message) { + this.property = property; + this.message = message; + } + + public String getProperty() { + return property; + } + + public void setProperty(String property) { + this.property = property; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((message == null) ? 0 : message.hashCode()); + result = prime * result + ((property == null) ? 0 : property.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Violation other = (Violation) obj; + if (message == null) { + if (other.message != null) + return false; + } else if (!message.equals(other.message)) + return false; + if (property == null) { + if (other.property != null) + return false; + } else if (!property.equals(other.property)) + return false; + return true; + } + + @Override + public String toString() { + return this.property + " " + this.message; + } + } +} diff --git a/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConstraintViolationExceptionMapper.java b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConstraintViolationExceptionMapper.java index d8be3fa..1e3ee6c 100644 --- a/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConstraintViolationExceptionMapper.java +++ b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/ConstraintViolationExceptionMapper.java @@ -1,50 +1,29 @@ -//package br.gov.frameworkdemoiselle.internal.implementation; -// -//import java.util.Arrays; -// -//import javax.validation.ConstraintViolation; -//import javax.validation.ConstraintViolationException; -//import javax.ws.rs.core.Context; -//import javax.ws.rs.core.Response; -//import javax.ws.rs.ext.ExceptionMapper; -//import javax.ws.rs.ext.Provider; -// -//@Provider -//public class ConstraintViolationExceptionMapper implements ExceptionMapper { -// -// @Context -// private Response response; -// -// @Override -// public Response toResponse(Exception exception) { -// -// Throwable rootCause = exception; -// while (rootCause != null) { -// if (rootCause instanceof ConstraintViolationException) { -// break; -// } -// -// rootCause = rootCause.getCause(); -// } -// -// if (rootCause != null) { -// for (ConstraintViolation violation : ((ConstraintViolationException) rootCause) -// .getConstraintViolations()) { -// String parts[] = violation.getPropertyPath().toString().split("\\.|\\[|\\]\\."); -// String property = null; -// -// if (parts.length > 1) { -// property = parts[1]; -// -// for (String part : Arrays.copyOfRange(parts, 2, parts.length)) { -// property += "." + part; -// } -// } -// -// System.out.println(property); -// } -// } -// -// return null; -// } -// } +package br.gov.frameworkdemoiselle.internal.implementation; + +import static javax.ws.rs.core.Response.Status.PRECONDITION_FAILED; + +import java.util.Iterator; + +import javax.validation.ConstraintViolation; +import javax.validation.ConstraintViolationException; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import br.gov.frameworkdemoiselle.PreconditionFailedException; + +@Provider +public class ConstraintViolationExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(ConstraintViolationException exception) { + PreconditionFailedException failed = new PreconditionFailedException(); + + for (Iterator> iter = exception.getConstraintViolations().iterator(); iter.hasNext();) { + ConstraintViolation violation = iter.next(); + failed.addViolation(violation.getPropertyPath().toString(), violation.getMessage()); + } + + return Response.status(PRECONDITION_FAILED).entity(failed.getViolations()).build(); + } +} diff --git a/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/PreconditionFailedExceptionMapper.java b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/PreconditionFailedExceptionMapper.java new file mode 100644 index 0000000..e461c21 --- /dev/null +++ b/impl/extension/rest/src/main/java/br/gov/frameworkdemoiselle/internal/implementation/PreconditionFailedExceptionMapper.java @@ -0,0 +1,16 @@ +package br.gov.frameworkdemoiselle.internal.implementation; + +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; + +import br.gov.frameworkdemoiselle.PreconditionFailedException; + +@Provider +public class PreconditionFailedExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(PreconditionFailedException exception) { + return Response.status(exception.getStatusCode()).entity(exception.getViolations()).build(); + } +} -- libgit2 0.21.2