/* * 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.openjpa.integration.validation; import java.lang.annotation.ElementType; import java.lang.reflect.Method; import java.security.AccessController; import java.util.HashMap; import java.util.Map; import javax.validation.ConstraintViolationException; import javax.validation.Path; import javax.validation.TraversableResolver; import junit.framework.TestCase; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.persistence.OpenJPAEntityManager; import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI; import org.apache.openjpa.persistence.OpenJPAPersistence; import org.apache.openjpa.persistence.validation.TraversableResolverImpl; // The following 2 are dynamically loaded by loadPathImpl() from setUp() // import org.hibernate.validator.engine.PathImpl; // import com.agimatec.validation.jsr303.util.PathImpl; /** * Test the TraversableResolver methods * * First run several testcases from a user perspective. These test the methods * indirectly: * 1) testLoadedTitle() * 2} testUnloaded() * 3) testCascading() * * Then test the methods directly: * 1) testPages() * 2) testTitle */ public class TestTraversableResolver extends TestCase { private static OpenJPAEntityManagerFactorySPI emf = null; private Log log = null; private OpenJPAEntityManager em = null; private Book book; /** * Create a book with a title that is too long, and the embedded * publisher has a name that is also too long. However, use a * persistence unit with validation-mode set to NONE. Therefore, * the create should be successful. This is to setup a situation * where fields to be potentially validated are not necessarily loaded. */ @Override public void setUp() { createBook(1, "long title", 234); } private void createEMF(String pu, String schemaAction) { Map<String, Object> map = new HashMap<String, Object>(); map.put("openjpa.jdbc.SynchronizeMappings", "buildSchema(ForeignKeys=true," + schemaAction); emf = (OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.createEntityManagerFactory( pu, "org/apache/openjpa/integration/validation/persistence.xml", map); assertNotNull(emf); log = emf.getConfiguration().getLog("Tests"); } private void closeEMF() { log = null; if (em != null) { em.close(); em = null; } if (emf != null) { emf.close(); emf = null; } } /** * By default, the title is not loaded. Make sure it gets loaded, * make a change in a different field, and commit. The isLoaded() method * of the TraversableResolver should return true, resulting in a validation * being performed and a ConstraintViolationException should be returned * because the title is too long. */ public void testLoadedTitle() { createEMF("validation-pu", "SchemaAction='add')"); em = emf.createEntityManager(); em.getTransaction().begin(); book = em.find(org.apache.openjpa.integration.validation.Book.class, 1); assertNotNull(book); book.setPages(124); // load the title String title = book.getTitle(); assertEquals("long title", title); boolean exceptionCaught = false; try { em.getTransaction().commit(); } catch (ConstraintViolationException e) { exceptionCaught = true; } assertTrue(exceptionCaught); } /** * By default, the title and publisher are not loaded. Make a change in a different field * and commit. The isLoaded() method of the TraversableResolver should return * false for both of these. Therefore a validation should not be performed. * The commit should succeed with no exception. */ public void testUnloaded() { createEMF("non-validation-pu", "SchemaAction='add')"); em = emf.createEntityManager(); em.getTransaction().begin(); book = em.find(org.apache.openjpa.integration.validation.Book.class, 1); assertNotNull(book); book.setPages(124); boolean exceptionCaught = false; try { em.getTransaction().commit(); } catch (ConstraintViolationException e) { exceptionCaught = true; } assertFalse(exceptionCaught); closeEMF(); } /** * By default, the publisher is not loaded. Make sure it gets loaded. * The isLoaded() and isCascadable() methods should both return true, * resulting in a validation being performed. A ConstraintViolation * should be thrown since the publisher name is too long. */ public void testCascading() { createEMF("validation-pu", "SchemaAction='add')"); em = emf.createEntityManager(); em.getTransaction().begin(); book = em.find(org.apache.openjpa.integration.validation.Book.class, 1); assertNotNull(book); book.setPages(124); // load the embedded publisher Publisher publisher = book.getPublisher(); assertNotNull(publisher); publisher.setPublisherID("yyy"); boolean exceptionCaught = false; try { em.getTransaction().commit(); } catch (Exception e) { exceptionCaught = true; } assertTrue(exceptionCaught); closeEMF(); } /** * Test the isReachable() and isCascadable() methods on the pages element of Book, * which is eagerly fetched by default. */ public void testPages() { createEMF("validation-pu", "SchemaAction='add')"); em = emf.createEntityManager(); em.getTransaction().begin(); book = em.find(org.apache.openjpa.integration.validation.Book.class, 1); assertNotNull(book); // PathImpl path = PathImpl.createPathFromString("org.apache.openjpa.integration.validation.Book.pages"); // Path.Node node = path.getLeafNode(); Path.Node node = getLeafNodeFromString("org.apache.openjpa.integration.validation.Book.pages"); TraversableResolver tr = new TraversableResolverImpl(); assertTrue(tr.isReachable(book, node, Book.class, null, ElementType.METHOD)); assertTrue(tr.isCascadable(book, node, Book.class, null, ElementType.METHOD)); em.getTransaction().commit(); closeEMF(); } /** * Test the isReachable() method on the title. * It is configured with fetch=FetvhType.LAZY. */ public void testTitle() { createEMF("validation-pu", "SchemaAction='add')"); em = emf.createEntityManager(); em.getTransaction().begin(); book = em.find(org.apache.openjpa.integration.validation.Book.class, 1); assertNotNull(book); // PathImpl path = PathImpl.createPathFromString("org.apache.openjpa.integration.validation.Book.title"); // Path.Node node = path.getLeafNode(); Path.Node node = getLeafNodeFromString("org.apache.openjpa.integration.validation.Book.title"); TraversableResolver tr = new TraversableResolverImpl(); assertFalse(tr.isReachable(book, node, Book.class, null, ElementType.FIELD)); em.getTransaction().commit(); closeEMF(); } private void createBook(int id, String title, int pages) { createEMF("non-validation-pu", "SchemaAction='drop,add')"); em = emf.createEntityManager(); book = new Book(id); book.setTitle(title); book.setPages(pages); Publisher publisher = new Publisher(); publisher.setName("long name"); publisher.setPublisherID("xxx"); book.setPublisher(publisher); em.getTransaction().begin(); em.persist(book); em.getTransaction().commit(); closeEMF(); } private Path.Node getLeafNodeFromString(String s) { Class<?> PathImpl = null; Path.Node node = null; // dynamically load PathImpl depending on the Bean Validation provider try { PathImpl = Class.forName("org.hibernate.validator.engine.PathImpl", true, AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction())); } catch (ClassNotFoundException e) { log.trace("getLeafNodeFromPath: Did not find org.hibernate.validator.engine.PathImpl"); } if (PathImpl == null) { try { PathImpl = Class.forName("org.apache.bval.jsr303.util.PathImpl", true, AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction())); } catch (ClassNotFoundException e) { log.trace("getLeafNodeFromPath: Did not find org.apache.bval.jsr303.util.PathImpl"); } } if (PathImpl == null) { try { PathImpl = Class.forName("com.agimatec.validation.jsr303.util.PathImpl", true, AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction())); } catch (ClassNotFoundException e) { log.trace("getLeafNodeFromPath: Did not find com.agimatec.validation.jsr303.util.PathImpl"); } } assertNotNull("Could not load a Bean Validation provider specific PathImpl", PathImpl); try { Method createPathFromString = PathImpl.getMethod("createPathFromString", String.class); assertNotNull(createPathFromString); Method getLeafNode = PathImpl.getMethod("getLeafNode"); assertNotNull(getLeafNode); Object path = createPathFromString.invoke(null, s); node = (Path.Node) getLeafNode.invoke(path, null); } catch (NoSuchMethodException e) { } catch (IllegalAccessException ae) { } catch (java.lang.reflect.InvocationTargetException te) { } return node; } }