blob: 04bc94f8d280ef8341b6de8d7f15f0fda7fa549e [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.models.company;
import java.beans.*;
import java.io.*;
import java.util.*;
import javax.persistence.*;
import junit.framework.*;
import org.apache.openjpa.persistence.test.*;
/**
* Generic test case that will be extended by a concrete company
* model subclass.
*
* @author Marc Prud'hommeaux
*/
public abstract class CompanyModelTest
extends SingleEMTestCase {
private static Map<Class,Class> factoryClasses;
private Map<Class,Class> impls;
public void setUp() {
// make a map of the implementations based on the class names in
// the current package of the test subclass
impls = new HashMap<Class,Class>();
impls.put(IAddress.class, localClass("Address"));
impls.put(ICompany.class, localClass("Company"));
impls.put(ICustomer.class, localClass("Customer"));
impls.put(IPerson.class, localClass("Person"));
impls.put(IEmployee.class, localClass("Employee"));
impls.put(IFullTimeEmployee.class, localClass("FullTimeEmployee"));
impls.put(ILineItem.class, localClass("LineItem"));
impls.put(IProductOrder.class, localClass("ProductOrder"));
impls.put(IPartTimeEmployee.class, localClass("PartTimeEmployee"));
impls.put(IProduct.class, localClass("Product"));
setUp(impls.values().toArray(new Class[impls.size()]));
checkModel();
}
private Class localClass(String name) {
String pkg = getClass().getPackage().getName();
try {
return Class.forName(pkg + "." + name);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
/**
* Runs through basic queries against all of the properties of all
* of the known persistent classes. We're just checking here to
* make sure the queries can be executed without problem. Queries
* should always return all known instances in the database.
*/
public void testBasicQueries() throws Exception {
for (Class c : impls.values()) {
for (PropertyDescriptor pd :
Introspector.getBeanInfo(c).getPropertyDescriptors()) {
if (pd.getWriteMethod() == null) // ignore read-only
continue;
Set<String> queries = new TreeSet<String>();
getBasicQueries(queries, pd, "x.");
StringBuilder str = new StringBuilder();
// execute the individual queries
for (String query : queries) {
find(c, "where " + query);
str.append(str.length() > 0 ? " or " : "").append(query);
}
// now execute all the queries combined
find(c, "where " + str);
}
}
}
void getBasicQueries(Set<String> queries, PropertyDescriptor pd,
String prefix) throws Exception {
// max level of field traversal: 3
// ### if (prefix.split("\\.").length > 3)
if (prefix.split("\\.").length > 2)
return;
Class type = pd.getPropertyType();
String name = prefix + pd.getName();
if (!queries.add(name + " is not null"))
return;
queries.add(name + " is null");
if (type.isAssignableFrom(Number.class) || type == int.class ||
type == double.class || type == float.class ||
type == long.class || type == short.class) {
queries.add(name + " = 0");
queries.add(name + " <> 0");
queries.add(name + " > 0");
queries.add(name + " < 0");
queries.add(name + " >= 0");
queries.add(name + " <= 0");
queries.add("sqrt(" + name + ") <> 0");
queries.add("abs(" + name + ") <> 0");
// queries.add("mod(" + name + ", 5) <> 0");
}
if (type.isAssignableFrom(Collection.class)) {
queries.add(name + " IS EMPTY");
queries.add(name + " IS NOT EMPTY");
queries.add("size(" + name + ") <> 0");
}
if (type.isAssignableFrom(String.class)) {
queries.add("lower(" + name + ") = 'x'");
queries.add("upper(" + name + ") = 'x'");
queries.add("concat(" + name + ", " + name + ") = 'x'");
queries.add("substring(" + name + ", 1, 2) = 'x'");
queries.add("length(" + name + ") > 0");
queries.add("locate(" + name + ", 'x', 1) > 0");
queries.add("trim(leading ' ' from " + name + ") = 'x'");
}
if (type.isAssignableFrom(Date.class)) {
queries.add(name + " <> CURRENT_TIMESTAMP");
}
// relation is an entity ... add all the relations
if (impls.containsKey(type) || impls.containsValue(type)) {
for (PropertyDescriptor desc :
Introspector.getBeanInfo(type).getPropertyDescriptors()) {
if (desc.getWriteMethod() == null) // ignore read-only
continue;
// prevent recursion
if (name.endsWith("." + desc.getName() + "."))
continue;
getBasicQueries(queries, desc, name + ".");
}
}
}
void checkModel() {
try {
verifyModel();
} catch (AssertionFailedError e) {
// clear all existing instances
clear(emf, impls.values().toArray(new Class[impls.size()]));
// since the factory method needs to be static, we need to store
// the classes statically
factoryClasses = impls;
try {
final List<Exception> exceptions = new LinkedList<Exception>();
XMLDecoder decoder = new XMLDecoder(CompanyModelTest.class.
getResourceAsStream("companies.xml"));
decoder.setExceptionListener(new ExceptionListener() {
public void exceptionThrown(Exception e) {
exceptions.add(e);
}
});
Collection obs = (Collection) decoder.readObject();
if (exceptions.size() > 0) {
throw new IllegalStateException(exceptions.get(0));
}
assertNotNull(obs);
persist(obs.toArray());
} finally {
factoryClasses = null;
}
}
verifyModel();
}
int queryCount(Class c, String query, Object... params) {
return find(c, query, params).size();
}
int queryCount(Class c) {
return find(c, null).size();
}
Class impl(Class c) {
return impls.get(c);
}
void verifyModel() {
assertEquals(2, queryCount(impl(ICompany.class)));
assertEquals(11, queryCount(impl(IAddress.class)));
assertEquals(3, queryCount(impl(IProduct.class)));
assertEquals(2, queryCount(impl(IProductOrder.class)));
assertEquals(3, queryCount(impl(ILineItem.class)));
assertEquals(1, queryCount(impl(IPartTimeEmployee.class)));
assertEquals(3, queryCount(impl(IFullTimeEmployee.class)));
assertEquals(4, queryCount(impl(ICustomer.class)));
assertEquals(3, queryCount(impl(IAddress.class),
"where x.state = 'CA'"));
assertEquals(1, queryCount(impl(ICompany.class),
"where size(x.employees) = 4"));
assertEquals(1, queryCount(impl(ICompany.class),
"where size(x.employees) = 0"));
assertEquals(2, queryCount(impl(ICustomer.class),
"where size(x.orders) = 1"));
assertEquals(1, queryCount(impl(IProductOrder.class),
"where x.shippedDate is null"));
assertEquals(1, queryCount(impl(IProductOrder.class),
"where x.shippedDate is not null"));
assertEquals(1, queryCount(impl(IEmployee.class),
"where x.manager is null"));
assertEquals(2, queryCount(impl(IEmployee.class),
"where x.manager.manager is null"));
assertEquals(1, queryCount(impl(IEmployee.class),
"where x.manager.manager.manager is null"));
assertEquals(2, queryCount(impl(IPerson.class),
"where x.firstName like ?1 and x.lastName like ?1", "M%"));
assertEquals(1, queryCount(impl(IPerson.class),
"where x.homeAddress.state = 'CA'"));
}
/**
* Factory method that is called from the serialized XML.
*/
public static Object create(Class intf)
throws InstantiationException, IllegalAccessException {
return factoryClasses.get(intf).newInstance();
}
}