| /* |
| * 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.persistence.jpql.expressions; |
| |
| import java.lang.reflect.Constructor; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import javax.persistence.EntityManager; |
| import javax.persistence.Query; |
| |
| import org.apache.openjpa.lib.log.Log; |
| import org.apache.openjpa.persistence.jpql.entities.IColumnEntity; |
| import org.apache.openjpa.persistence.jpql.entities.INameEntity; |
| import org.apache.openjpa.persistence.jpql.entities.IOrderedElements; |
| import org.apache.openjpa.persistence.jpql.entities.IOrderedEntity; |
| import org.apache.openjpa.persistence.jpql.entities.OrderedElementEntity; |
| import org.apache.openjpa.persistence.jpql.entities.OrderedManyToManyEntity; |
| import org.apache.openjpa.persistence.jpql.entities.OrderedNameEntity; |
| import org.apache.openjpa.persistence.jpql.entities.OrderedOneToManyEntity; |
| import org.apache.openjpa.persistence.jpql.entities.UnorderedNameEntity; |
| import org.apache.openjpa.persistence.jpql.entities.XMLOrderedElementEntity; |
| import org.apache.openjpa.persistence.jpql.entities.XMLOrderedManyToManyEntity; |
| import org.apache.openjpa.persistence.jpql.entities.XMLOrderedNameEntity; |
| import org.apache.openjpa.persistence.jpql.entities.XMLOrderedOneToManyEntity; |
| import org.apache.openjpa.persistence.jpql.entities.XMLUnorderedNameEntity; |
| import org.apache.openjpa.persistence.proxy.TreeNode; |
| import org.apache.openjpa.persistence.test.JPAEntityClassEnum; |
| import org.apache.openjpa.persistence.test.SingleEMFTestCase; |
| |
| /** |
| * Test JPQL Index function on O2M, M2M and Element collections using annotations and XML. |
| * |
| * @author Catalina Wei, Albert Lee, Donald Woods |
| */ |
| public class TestIndex extends SingleEMFTestCase { |
| |
| private Log log = null; |
| |
| private enum JPQLIndexEntityClasses implements JPAEntityClassEnum { |
| OrderedElementEntity(OrderedElementEntity.class), |
| OrderedOneToManyEntity(OrderedOneToManyEntity.class), |
| OrderedManyToManyEntity(OrderedManyToManyEntity.class), |
| XMLOrderedElementEntity(XMLOrderedElementEntity.class), |
| XMLOrderedOneToManyEntity(XMLOrderedOneToManyEntity.class), |
| XMLOrderedManyToManyEntity(XMLOrderedManyToManyEntity.class), |
| UnorderedNameEntity(UnorderedNameEntity.class), |
| XMLUnorderedNameEntity(XMLUnorderedNameEntity.class), |
| OrderedNameEntity(OrderedNameEntity.class); |
| |
| private Class<?> clazz; |
| private String fullEntityName; |
| private String entityName; |
| |
| JPQLIndexEntityClasses(Class<?> clazz) { |
| this.clazz = clazz; |
| fullEntityName = clazz.getName(); |
| entityName = fullEntityName.substring(getEntityClassName() |
| .lastIndexOf('.') + 1); |
| } |
| |
| public Class<?> getEntityClass() { |
| return clazz; |
| } |
| |
| @Override |
| public String getEntityClassName() { |
| return fullEntityName; |
| } |
| |
| @Override |
| public String getEntityName() { |
| return entityName; |
| } |
| } |
| |
| private static final String[] Element_Names = { "A_Element", "B_Element", |
| "C_Element", "D_Element", "E_Element", "F_Element", }; |
| |
| @Override |
| protected String getPersistenceUnitName() { |
| // this sets up the testcase code so our EMF is created and cleaned up for us |
| return "JPQLIndex"; |
| } |
| |
| @Override |
| public void setUp() { |
| super.setUp(CLEAR_TABLES, TreeNode.class, |
| OrderedElementEntity.class, UnorderedNameEntity.class, |
| OrderedOneToManyEntity.class, OrderedManyToManyEntity.class, |
| OrderedNameEntity.class); |
| // XMLOrderedOneToManyEntity.class, XMLOrderedManyToManyEntity.class, |
| // XMLOrderedElementEntity.class, XMLUnorderedNameEntity.class, |
| // XMLOrderedNameEntity.class); |
| |
| log = emf.getConfiguration().getLog("test"); |
| } |
| |
| // original testcase by Catalina |
| public void testO2MTreeQueryIndex() { |
| int[] fanOuts = {2,3,4}; |
| createTreeNodeEntities(fanOuts); |
| EntityManager em = emf.createEntityManager(); |
| String query = "SELECT index(c) from TreeNode t, in (t.childern) c" + |
| " WHERE index(c) = 2"; |
| |
| List<Object> rs = em.createQuery(query).getResultList(); |
| for (Object t: rs) |
| assertEquals(2, Integer.parseInt(t.toString())); |
| |
| em.close(); |
| } |
| |
| // Testcases added by Donald with code reused from annonxml tests by Albert |
| public void testO2MQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.OrderedOneToManyEntity, UnorderedNameEntity.class); |
| verifyEntities(JPQLIndexEntityClasses.OrderedOneToManyEntity, UnorderedNameEntity.class); |
| } |
| |
| public void testO2MXMLQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.XMLOrderedOneToManyEntity, XMLUnorderedNameEntity.class); |
| verifyEntities(JPQLIndexEntityClasses.XMLOrderedOneToManyEntity, XMLUnorderedNameEntity.class); |
| } |
| |
| public void testM2MQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.OrderedManyToManyEntity, OrderedNameEntity.class); |
| verifyEntities(JPQLIndexEntityClasses.OrderedManyToManyEntity, OrderedNameEntity.class); |
| } |
| |
| public void testM2MXMLQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.OrderedManyToManyEntity, XMLOrderedNameEntity.class); |
| verifyEntities(JPQLIndexEntityClasses.OrderedManyToManyEntity, XMLOrderedNameEntity.class); |
| } |
| |
| public void testElementQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.OrderedElementEntity, String.class); |
| verifyEntities(JPQLIndexEntityClasses.OrderedElementEntity, String.class); |
| } |
| |
| public void testElementXMLQueryIndex() { |
| createEntities(JPQLIndexEntityClasses.XMLOrderedElementEntity, String.class); |
| verifyEntities(JPQLIndexEntityClasses.XMLOrderedElementEntity, String.class); |
| } |
| |
| /** |
| * Create and persist a uniform OneToMany tree with given fan out. |
| */ |
| private TreeNode createTreeNodeEntities(int[] original) { |
| TreeNode root = new TreeNode(); |
| root.createTree(original); |
| assertArrayEquals(original, root.getFanOuts()); |
| |
| EntityManager em = emf.createEntityManager(); |
| em.getTransaction().begin(); |
| em.persist(root); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| return root; |
| } |
| |
| /** |
| * Asserts the given arrays have exactly same elements at the same index. |
| */ |
| private void assertArrayEquals(int[] a, int[] b) { |
| assertEquals(a.length, b.length); |
| for (int i = 0; i<a.length; i++) |
| assertEquals(a[i], b[i]); |
| } |
| |
| private <C,E> void createEntities(JPQLIndexEntityClasses entityType, Class<E> elementClass) |
| { |
| if (IOrderedEntity.class.isAssignableFrom(entityType.getEntityClass())) { |
| if (INameEntity.class.isAssignableFrom(elementClass)) { |
| log.trace("** Test INameEntity modifications on IOrderedEntity."); |
| createO2MEntities(entityType, (Class<INameEntity>)elementClass); |
| } else if (IColumnEntity.class.isAssignableFrom(elementClass)) { |
| log.trace("** Test IColumnEntity modifications on IOrderedEntity."); |
| createM2MEntities(entityType, (Class<IColumnEntity>)elementClass); |
| } else { |
| fail("createEntities(IOrderedEntity) - Unexpected elementClass=" + elementClass.getSimpleName()); |
| } |
| } else if (IOrderedElements.class.isAssignableFrom(entityType.getEntityClass())) { |
| if (String.class.isAssignableFrom(elementClass)) { |
| log.trace("** Test String modifications on IOrderedElements."); |
| createOrderedElements(entityType); |
| } else { |
| fail("createEntities(IOrderedElements) - Unexpected elementClass=" + elementClass.getSimpleName()); |
| } |
| } else { |
| fail("createEntities() - Unexpected entityType=" + entityType.getEntityName()); |
| } |
| } |
| |
| private void createO2MEntities(JPQLIndexEntityClasses entityType, Class<INameEntity> elementClass) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedEntity> entityClass = |
| (Class<IOrderedEntity>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| String elementClassName = elementClass.getName().substring( |
| elementClass.getName().lastIndexOf('.') + 1); |
| Integer entityId = 1; |
| |
| // create the entity |
| IOrderedEntity newEntity = (IOrderedEntity)constructNewEntityObject(entityType); |
| newEntity.setId(entityId); |
| |
| // create the elements to add |
| Constructor<INameEntity> elementConstrctor = elementClass.getConstructor(String.class); |
| List<INameEntity> newElements = new ArrayList<>(); |
| for (String element_name : Element_Names) { |
| newElements.add(elementConstrctor.newInstance(element_name)); |
| } |
| |
| // add the entities |
| em = emf.createEntityManager(); |
| em.getTransaction().begin(); |
| for (INameEntity newElement : newElements) |
| { |
| em.persist(newElement); |
| newEntity.addEntity((INameEntity)newElement); |
| } |
| em.persist(newEntity); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| // verify the entity was stored |
| IOrderedEntity findEntity = em.find(entityClass, entityId); |
| assertNotNull("Found entity just created", findEntity); |
| assertEquals("Verify entity id = " + entityId, entityId.intValue(), findEntity.getId()); |
| assertEquals("Verify entity name = " + entityClass.getName(), entityClass.getName(), |
| findEntity.getClass().getName()); |
| |
| } catch (Throwable t) { |
| log.error(t); |
| throw new RuntimeException(t); |
| } finally { |
| if (em != null) { |
| if (em.getTransaction().isActive()) { |
| em.getTransaction().rollback(); |
| } |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| private void createM2MEntities(JPQLIndexEntityClasses entityType, Class<IColumnEntity> elementClass) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedEntity> entityClass = |
| (Class<IOrderedEntity>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| String elementClassName = elementClass.getName().substring( |
| elementClass.getName().lastIndexOf('.') + 1); |
| |
| // create the EM and transaction |
| em = emf.createEntityManager(); |
| em.getTransaction().begin(); |
| |
| // create and persist the entities |
| List<IOrderedEntity> newEntities = new ArrayList<>(); |
| for (int i=0; i<3; i++) { |
| IOrderedEntity newEntity = (IOrderedEntity)constructNewEntityObject(entityType); |
| newEntity.setId(i); |
| em.persist(newEntity); |
| newEntities.add(newEntity); |
| } |
| |
| // create and persist the elements |
| Constructor<IColumnEntity> elementConstrctor = elementClass.getConstructor(String.class); |
| List<INameEntity> newElements = new ArrayList<>(); |
| IColumnEntity newElement; |
| for (String element_name : Element_Names) { |
| newElement = elementConstrctor.newInstance(element_name); |
| // add parent relationships |
| newElement.setEntities(newEntities); |
| em.persist(newElement); |
| newElements.add(newElement); |
| } |
| |
| // update entities with elements |
| for (IOrderedEntity newEntity : newEntities) { |
| newEntity.setEntities(newElements); |
| em.persist(newEntity); |
| } |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| // verify the entities were stored |
| for (int i=0; i<Element_Names.length; i++) { |
| IOrderedEntity findEntity = em.find(entityClass, i); |
| assertNotNull("Found entity just created", findEntity); |
| assertEquals("Verify entity id = " + i, i, findEntity.getId()); |
| assertEquals("Verify entity name = " + entityClass.getName(), entityClass.getName(), |
| findEntity.getClass().getName()); |
| } |
| } catch (Throwable t) { |
| log.error(t); |
| throw new RuntimeException(t); |
| } finally { |
| if (em != null) { |
| if (em.getTransaction().isActive()) { |
| em.getTransaction().rollback(); |
| } |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| private void createOrderedElements(JPQLIndexEntityClasses entityType) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedElements> entityClass = |
| (Class<IOrderedElements>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| Integer entityId = 1; |
| |
| IOrderedElements newEntity = (IOrderedElements)constructNewEntityObject(entityType); |
| newEntity.setId(entityId); |
| List<String> namesList = new ArrayList<>(); |
| for (String element_name : Element_Names) { |
| namesList.add(element_name); |
| } |
| newEntity.setListElements(namesList); |
| // add the entity |
| em = emf.createEntityManager(); |
| em.getTransaction().begin(); |
| em.persist(newEntity); |
| em.getTransaction().commit(); |
| em.clear(); |
| |
| // verify the entity was stored |
| log.trace("Verifing the entity was stored"); |
| IOrderedElements findEntity = em.find(entityClass, entityId); |
| assertNotNull("Found entity just created", findEntity); |
| assertEquals("Verify entity id = " + entityId, entityId.intValue(), findEntity.getId()); |
| assertEquals("Verify entity name = " + entityClass.getName(), entityClass.getName(), |
| findEntity.getClass().getName()); |
| |
| } catch (Throwable t) { |
| log.error(t); |
| throw new RuntimeException(t); |
| } finally { |
| if (em != null) { |
| if (em.getTransaction().isActive()) { |
| em.getTransaction().rollback(); |
| } |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| private <C,E> void verifyEntities(JPQLIndexEntityClasses entityType, Class<E> elementClass) |
| { |
| if (IOrderedEntity.class.isAssignableFrom(entityType.getEntityClass())) { |
| if (INameEntity.class.isAssignableFrom(elementClass)) { |
| log.trace("** Verify INameEntity modifications on IOrderedEntity."); |
| verifyO2MEntities(entityType, (Class<INameEntity>)elementClass); |
| } else if (IColumnEntity.class.isAssignableFrom(elementClass)) { |
| log.trace("** Verify IColumnEntity modifications on IOrderedEntity."); |
| verifyM2MEntities(entityType, (Class<IColumnEntity>)elementClass); |
| } else { |
| fail("verifyEntities(IOrderedEntity) - Unexpected elementClass=" + elementClass.getSimpleName()); |
| } |
| } else if (IOrderedElements.class.isAssignableFrom(entityType.getEntityClass())) { |
| if (String.class.isAssignableFrom(elementClass)) { |
| log.trace("** Test String modifications on IOrderedElements."); |
| verifyOrderedElements(entityType); |
| } else { |
| fail("verifyEntities(IOrderedElements) - Unexpected elementClass=" + elementClass.getSimpleName()); |
| } |
| } else { |
| fail("verifyEntities() - Unexpected entityType=" + entityType.getEntityName()); |
| } |
| } |
| |
| private <E> void verifyO2MEntities(JPQLIndexEntityClasses entityType, Class<INameEntity> elementClass) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedEntity> entityClass = (Class<IOrderedEntity>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| entityClassName = entityClassName.substring(entityClassName.lastIndexOf('.') + 1); |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Query " + entityClassName + " and verify 'entities' collection has " |
| + Element_Names.length + " elements in this order: " |
| + Arrays.toString(Element_Names)); |
| } |
| |
| em = emf.createEntityManager(); |
| em.clear(); |
| int idx = 0; |
| for (String expectedEntityName : Element_Names) { |
| Query q = em.createQuery("select w from " + entityClassName |
| + " o join o.entities w where index(w) = " + idx); |
| List<E> res = (List<E>)q.getResultList(); |
| assertEquals(" Verify query returns 1 element for index " + idx, 1, res.size()); |
| if (res.size() == 1) { |
| Object oo = res.get(0); |
| assertEquals(" Verify element type is " + elementClass.getName(), elementClass.getName(), |
| oo.getClass().getName()); |
| try { |
| String name = (String) elementClass.getMethod("getName").invoke(oo); |
| assertEquals(" Verify element value is '" |
| + expectedEntityName + "'", expectedEntityName, name); |
| } catch (Exception e) { |
| log.error(" Caught unexpected exception:" + e.getMessage()); |
| throw new RuntimeException(e); |
| } |
| } |
| ++idx; |
| } |
| } catch (Exception e) { |
| log.error(e); |
| throw new RuntimeException(e); |
| } finally { |
| if (em != null) { |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| private <E> void verifyM2MEntities(JPQLIndexEntityClasses entityType, Class<IColumnEntity> elementClass) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedEntity> entityClass = (Class<IOrderedEntity>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| entityClassName = entityClassName.substring(entityClassName.lastIndexOf('.') + 1); |
| String elementClassName = entityType.getEntityName(); |
| elementClassName = elementClassName.substring(elementClassName.lastIndexOf('.') + 1); |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Query " + entityClassName + " and verify 'entities' collection has " |
| + Element_Names.length + " elements in this order: " |
| + Arrays.toString(Element_Names)); |
| } |
| |
| em = emf.createEntityManager(); |
| em.clear(); |
| int idx = 0, idx2 = 0; |
| for (String expectedEntityName : Element_Names) { |
| Query q = em.createQuery("select w from " + entityClassName |
| + " o join o.entities w where index(w) = " + idx); |
| List<E> res = (List<E>)q.getResultList(); |
| assertEquals(" Verify query returns 1 element for index " + idx, 1, res.size()); |
| if (res.size() == 1) { |
| Object oo = res.get(0); |
| assertEquals(" Verify element type is " + elementClass.getName(), elementClass.getName(), |
| oo.getClass().getName()); |
| try { |
| String name = (String) elementClass.getMethod("getName").invoke(oo); |
| assertEquals(" Verify element value is '" |
| + expectedEntityName + "'", expectedEntityName, name); |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Query " + elementClassName + " and verify 'entities' collection content"); |
| } |
| Query q2 = em.createQuery("select w from " + elementClassName |
| + " o join o.entities w where index(w) = " + idx2); |
| List<E> res2 = (List<E>)q.getResultList(); |
| assertEquals(" Verify query returns 1 entity for index " + idx2, 1, res2.size()); |
| if (res2.size() == 1) { |
| Object oo2 = res2.get(0); |
| assertEquals(" Verify entity type is " + entityClass.getName(), entityClass.getName(), |
| oo2.getClass().getName()); |
| try { |
| String name2 = (String) entityClass.getMethod("getName").invoke(oo2); |
| assertEquals(" Verify entity value is '" |
| + expectedEntityName + "'", expectedEntityName, name); |
| } catch (Exception e) { |
| log.error(" Caught unexpected exception:" + e.getMessage()); |
| throw new RuntimeException(e); |
| } |
| } |
| } catch (Exception e) { |
| log.error(" Caught unexpected exception:" + e.getMessage()); |
| throw new RuntimeException(e); |
| } |
| } |
| ++idx; |
| } |
| } catch (Exception e) { |
| log.error(e); |
| throw new RuntimeException(e); |
| } finally { |
| if (em != null) { |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| private <E> void verifyOrderedElements(JPQLIndexEntityClasses entityType) |
| { |
| EntityManager em = null; |
| |
| try { |
| Class<IOrderedEntity> entityClass = (Class<IOrderedEntity>)Class.forName(entityType.getEntityClassName()); |
| String entityClassName = entityType.getEntityName(); |
| entityClassName = entityClassName.substring(entityClassName.lastIndexOf('.') + 1); |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Query " + entityClassName + " and verify 'elements' collection has " |
| + Element_Names.length + " elements in this order: " |
| + Arrays.toString(Element_Names)); |
| } |
| |
| em = emf.createEntityManager(); |
| em.clear(); |
| int idx = 0; |
| for (String expectedEntityName : Element_Names) { |
| Query q = em.createQuery("select w from " + entityClassName |
| + " o join o.elements w where index(w) = " + idx); |
| List<E> res = (List<E>)q.getResultList(); |
| assertEquals(" Verify query returns 1 element for index " + idx, 1, res.size()); |
| if (res.size() == 1) { |
| Object oo = res.get(0); |
| assertEquals(" Verify element type is String", String.class.getName(), |
| oo.getClass().getName()); |
| String name; |
| try { |
| name = (String) oo.toString(); |
| assertEquals(" Verify element value is '" |
| + expectedEntityName + "'", expectedEntityName, name); |
| } catch (Exception e) { |
| log.error(" Caught unexpected exception:" + e.getMessage()); |
| throw new RuntimeException(e); |
| } |
| } |
| ++idx; |
| } |
| } catch (Exception e) { |
| log.error(e); |
| throw new RuntimeException(e); |
| } finally { |
| if (em != null) { |
| em.close(); |
| em = null; |
| } |
| } |
| } |
| |
| } |