Author: jlmonteiro
Date: Tue May 10 11:42:49 2011
New Revision: 1101415
URL: http://svn.apache.org/viewvc?rev=1101415&view=rev
Log:
OPENEJB:1525 bean validation appendix.
Thanks Romain.
Added:
openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/
openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/BeanValidationAppendixInterceptor.java
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/BeanContextSystemInterceptorTest.java
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationAppendixInterceptorTest.java
Modified:
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationTest.java
Added:
openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/BeanValidationAppendixInterceptor.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/BeanValidationAppendixInterceptor.java?rev=1101415&view=auto
==============================================================================
---
openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/BeanValidationAppendixInterceptor.java
(added)
+++
openejb/branches/openejb-3.2.x/container/openejb-core/src/main/java/org/apache/openejb/bval/BeanValidationAppendixInterceptor.java
Tue May 10 11:42:49 2011
@@ -0,0 +1,173 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb.bval;
+
+
+import org.apache.openejb.core.ivm.naming.NamingException;
+import org.apache.openejb.util.LogCategory;
+import org.apache.openejb.util.Logger;
+
+import javax.interceptor.AroundInvoke;
+import javax.interceptor.InvocationContext;
+import javax.naming.InitialContext;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.ValidationException;
+import javax.validation.Validator;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * A simple interceptor to validate parameters and returned value using
+ * bean validation spec. It doesn't use group for now.
+ * <p/>
+ * It is dependent of the Apache Bean Validation implementation.
+ *
+ * @author Romain Manni-Bucau
+ */
+public class BeanValidationAppendixInterceptor {
+ private static final Logger logger =
Logger.getInstance(LogCategory.OPENEJB,
BeanValidationAppendixInterceptor.class);
+ private static final Class<?> APACHE_BVAL_METHOD_CLASS = initApache();
+ private static final Class<?> HIBERNATE_METHOD_CLASS = initHibernate();
+
+ @AroundInvoke
+ public Object aroundInvoke(final InvocationContext ejbContext) throws
Exception {
+ Object validatorObject = null;
+ Validator validator = null;
+ try {
+ validator = (Validator) new
InitialContext().lookup("java:comp/Validator");
+ } catch (NamingException ne) {
+ // no-op
+ }
+
+ Set<?> violations = Collections.emptySet();
+ if (APACHE_BVAL_METHOD_CLASS != null && validator != null) {
+ validatorObject = validator.unwrap(APACHE_BVAL_METHOD_CLASS);
+ violations = call(Set.class, validatorObject, "validateParameters",
+ new Object[]{
+ ejbContext.getTarget().getClass(),
ejbContext.getMethod(), ejbContext.getParameters(), new Class[0]
+ },
+ new Class<?>[]{
+ Class.class, Method.class, Object[].class,
Class[].class
+ });
+ } else if (HIBERNATE_METHOD_CLASS != null && validator != null) {
+ validatorObject = validator.unwrap(HIBERNATE_METHOD_CLASS);
+ violations = call(Set.class, validatorObject,
"validateAllParameters",
+ new Object[]{
+ ejbContext.getTarget(), ejbContext.getMethod(),
ejbContext.getParameters(), new Class[0]
+ },
+ new Class<?>[]{
+ Object.class, Method.class, Object[].class,
Class[].class
+ });
+ } else { // a warning message to inform Apache Bean Validation is not
present
+ if (validator == null) {
+ logger.error("can't find validator");
+ } else {
+ logger.warning("Apache Bean Validation is not present, "
+ + BeanValidationAppendixInterceptor.class.getName() +
" will not work. "
+ + "Please put it if you want to validate your
parameters and returned values "
+ + "with bean validation JSR.");
+ }
+ }
+
+ if (violations.size() > 0) {
+ throw buildValidationException((Set<ConstraintViolation<?>>)
violations);
+ }
+
+ Object returnedValue = ejbContext.proceed();
+
+ violations = Collections.emptySet();
+ if (validatorObject != null && APACHE_BVAL_METHOD_CLASS != null) {
+ violations = call(Set.class, validatorObject,
"validateReturnedValue",
+ new Object[]{
+ ejbContext.getTarget().getClass(),
ejbContext.getMethod(), returnedValue, new Class[0]
+ },
+ new Class<?>[]{
+ Class.class, Method.class, Object.class,
Class[].class
+ });
+ } else if (validatorObject != null && HIBERNATE_METHOD_CLASS != null) {
+ violations = call(Set.class, validatorObject,
"validateReturnValue",
+ new Object[]{
+ ejbContext.getTarget(), ejbContext.getMethod(),
returnedValue, new Class[0]
+ },
+ new Class<?>[]{
+ Object.class, Method.class, Object.class,
Class[].class
+ });
+ }
+
+ if (violations.size() > 0) {
+ throw buildValidationException((Set<ConstraintViolation<?>>)
violations);
+ }
+
+ return returnedValue;
+ }
+
+ // just a simple EJBException for now
+ private RuntimeException
buildValidationException(Set<ConstraintViolation<?>> violations) {
+ return new ConstraintViolationException(violations);
+ }
+
+ private static <T> T call(Class<T> returnedType, Object o, String
methodName, Object[] params, Class<?>[] types) {
+ Method method = null;
+ boolean accessible = true;
+ try {
+ method = o.getClass().getMethod(methodName, types);
+ accessible = method.isAccessible();
+ if (!accessible) {
+ accessible = false;
+ method.setAccessible(true);
+ }
+ return (T) method.invoke(o, params);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new ValidationException("can't call method " + methodName +
" on " + o, e);
+ } finally {
+ if (method != null) {
+ method.setAccessible(accessible);
+ }
+ }
+ }
+
+ private static ClassLoader getClassLaoder() {
+ ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader =
BeanValidationAppendixInterceptor.class.getClassLoader();
+ }
+ return classLoader;
+ }
+
+ private static Class<?> initApache() {
+ try {
+ return
getClassLaoder().loadClass("org.apache.bval.jsr303.extensions.MethodValidator");
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+
+ private static Class<?> initHibernate() {
+ ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ classLoader =
BeanValidationAppendixInterceptor.class.getClassLoader();
+ }
+ try {
+ return
getClassLaoder().loadClass("org.hibernate.validator.method.MethodValidator");
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+}
\ No newline at end of file
Added:
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/BeanContextSystemInterceptorTest.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/BeanContextSystemInterceptorTest.java?rev=1101415&view=auto
==============================================================================
---
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/BeanContextSystemInterceptorTest.java
(added)
+++
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/BeanContextSystemInterceptorTest.java
Tue May 10 11:42:49 2011
@@ -0,0 +1,94 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.openejb;
+
+import org.apache.openejb.bval.BeanValidationAppendixInterceptor;
+import org.apache.openejb.core.CoreDeploymentInfo;
+import org.apache.openejb.jee.EmptyType;
+import org.apache.openejb.jee.StatelessBean;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.junit.Configuration;
+import org.apache.openejb.junit.Module;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.ejb.EJB;
+import javax.ejb.LocalBean;
+import javax.ejb.Stateless;
+import javax.validation.ConstraintViolationException;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Properties;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+/**
+ * @author Romain Manni-Bucau
+ */
+@RunWith(ApplicationComposer.class)
+public class BeanContextSystemInterceptorTest {
+ @EJB private Manager manager;
+
+ @Configuration public Properties config() {
+ final Properties p = new Properties();
+ p.put(CoreDeploymentInfo.USER_DEFAULT_INTERCEPTOR_KEY,
BeanValidationAppendixInterceptor.class.getName());
+ return p;
+ }
+
+ @Module public StatelessBean app() throws Exception {
+ final StatelessBean bean = new StatelessBean(Manager.class);
+ bean.setLocalBean(new EmptyType());
+ return bean;
+ }
+
+ @LocalBean
+ @Stateless
+ public static class Manager {
+ @Size(min = 1, max = 5) @NotNull public String
shouldBeValidated(String returned, @Max(5) int param) {
+ return returned;
+ }
+ }
+
+ @Test public void valid() {
+ manager.shouldBeValidated("hi", 1);
+ }
+
+ @Test public void notValid() {
+ try {
+ manager.shouldBeValidated(null, 1);
+ fail();
+ } catch (Exception ejbException) {
+ assertTrue(ejbException.getCause() instanceof
ConstraintViolationException);
+ ConstraintViolationException constraintViolationException =
(ConstraintViolationException) ejbException.getCause();
+ assertEquals(1,
constraintViolationException.getConstraintViolations().size());
+ }
+ }
+
+ @Test public void notValid2() throws Exception {
+ try {
+ manager.shouldBeValidated("hello", 6);
+ fail();
+ } catch (Exception ejbException) {
+ assertTrue(ejbException.getCause() instanceof
ConstraintViolationException);
+ ConstraintViolationException constraintViolationException =
(ConstraintViolationException) ejbException.getCause();
+ assertEquals(1,
constraintViolationException.getConstraintViolations().size());
+ }
+ }
+}
Added:
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationAppendixInterceptorTest.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationAppendixInterceptorTest.java?rev=1101415&view=auto
==============================================================================
---
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationAppendixInterceptorTest.java
(added)
+++
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationAppendixInterceptorTest.java
Tue May 10 11:42:49 2011
@@ -0,0 +1,82 @@
+package org.apache.openejb.bval;
+
+import org.apache.openejb.jee.EmptyType;
+import org.apache.openejb.jee.StatelessBean;
+import org.apache.openejb.junit.ApplicationComposer;
+import org.apache.openejb.junit.Module;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import javax.ejb.EJB;
+import javax.ejb.LocalBean;
+import javax.ejb.Stateless;
+import javax.interceptor.Interceptors;
+import javax.validation.ConstraintViolationException;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Romain Manni-Bucau
+ */
+@RunWith(ApplicationComposer.class)
+public class BeanValidationAppendixInterceptorTest {
+ @EJB private ValidationManager validationManager;
+
+ @Module public StatelessBean bean() throws Exception {
+ final StatelessBean bean = new StatelessBean(ValidationManager.class);
+ bean.setLocalBean(new EmptyType());
+ return bean;
+ }
+
+ @LocalBean
+ @Stateless
+ @Interceptors(BeanValidationAppendixInterceptor.class)
+ public static class ValidationManager {
+ @Min(0) public int valid(@Size(max = 1) @NotNull String
complicatedName, @Max(5) int ret) {
+ return ret;
+ }
+ }
+
+ @Test public void valid() {
+ validationManager.valid("", 1);
+ }
+
+ @Test public void paramNotValid() {
+ try {
+ validationManager.valid(":(", 1);
+ fail();
+ } catch (Exception exception) {
+ assertTrue(exception.getCause() instanceof
ConstraintViolationException);
+ ConstraintViolationException validationException =
(ConstraintViolationException) exception.getCause();
+ assertEquals(1,
validationException.getConstraintViolations().size());
+ }
+ }
+
+ @Test public void returnedNotValid() {
+ try {
+ validationManager.valid("", -1);
+ fail();
+ } catch (Exception exception) {
+ assertTrue(exception.getCause() instanceof
ConstraintViolationException);
+ ConstraintViolationException validationException =
(ConstraintViolationException) exception.getCause();
+ assertEquals(1,
validationException.getConstraintViolations().size());
+ }
+ }
+
+ @Test public void paramNotValid2() {
+ try {
+ validationManager.valid(null, 6);
+ fail();
+ } catch (Exception exception) {
+ assertTrue(exception.getCause() instanceof
ConstraintViolationException);
+ ConstraintViolationException validationException =
(ConstraintViolationException) exception.getCause();
+ assertEquals(2,
validationException.getConstraintViolations().size());
+ }
+ }
+}
Modified:
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationTest.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationTest.java?rev=1101415&r1=1101414&r2=1101415&view=diff
==============================================================================
---
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationTest.java
(original)
+++
openejb/branches/openejb-3.2.x/container/openejb-core/src/test/java/org/apache/openejb/bval/BeanValidationTest.java
Tue May 10 11:42:49 2011
@@ -1,3 +1,19 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.apache.openejb.bval;
import org.apache.openejb.jee.EmptyType;