blob: 60fc864564e6fa456840aa850b1feb925f325b54 [file] [log] [blame]
/*
* 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;
}
}
}
}