OPENJPA-1045. L2 cache included / excluded types may be specified via configuration properties

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@770729 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Michael Dick 2009-05-01 15:47:33 +00:00
parent 733c1ea7de
commit 2c2e78149d
6 changed files with 569 additions and 3 deletions

View File

@ -19,13 +19,17 @@
package org.apache.openjpa.datacache;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.event.RemoteCommitEvent;
import org.apache.openjpa.event.RemoteCommitListener;
@ -35,6 +39,8 @@ import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.concurrent.AbstractConcurrentEventManager;
import serp.util.Strings;
/**
* Abstract {@link DataCache} implementation that provides various
* statistics, logging, and timeout functionality common across cache
@ -69,6 +75,9 @@ public abstract class AbstractDataCache
private boolean _closed = false;
private String _schedule = null;
protected Set<String> _includedTypes;
protected Set<String> _excludedTypes;
public String getName() {
return _name;
}
@ -461,4 +470,73 @@ public abstract class AbstractDataCache
log.warn(s_loc.get("exp-listener-ex"), e);
}
}
public Set<String> getTypes() {
return _includedTypes;
}
public Set<String> getExcludedTypes() {
return _excludedTypes;
}
public void setTypes(Set<String> types) {
_includedTypes = types;
}
public void setTypes(String types) {
_includedTypes =
StringUtils.isEmpty(types) ? null : new HashSet<String>(Arrays
.asList(Strings.split(types, ";", 0)));
}
public void setExcludedTypes(Set<String> types) {
_excludedTypes = types;
}
public void setExcludedTypes(String types) {
_excludedTypes =
StringUtils.isEmpty(types) ? null : new HashSet<String>(Arrays
.asList(Strings.split(types, ";", 0)));
}
/**
* Determine whether a provided class can be applied to this cache.
*
* <P>
* The algorithm used to determine which types apply is as follows:
* <UL>
* <LI>If neither included nor excluded types are found all types will be
* used.</LI>
* <LI>If included types are specified and excluded types are not specified
* <b>only</b> the included types will be used.</LI>
* <LI>If included types are not specified and excluded types are specified
* all types will be used <b>except</b> those which are explicitly excluded.
* </LI>
* <LI>If both included types and excluded types are specified then
* <b>only</b> the included types will be used. If an included type is also
* an excluded type the <b>excluded</b> setting will take precedence (ie
* the type will not be used).</LI>
* </UL>
*
* @param className
* A class which may be used by this plugin.
* @return True if the type should be used, otherwise false.
*/
public boolean isCacheableType(String classname) {
boolean rval = true;
if(rval) {
System.out.format("ABDC");
}
if (_includedTypes != null && ! _includedTypes.isEmpty()) {
if(!_includedTypes.contains(classname)) {
rval = false;
}
}
if (_excludedTypes != null && ! _excludedTypes.isEmpty()) {
if(_excludedTypes.contains(classname)) {
rval = false;
}
}
return rval;
}
}

View File

@ -38,6 +38,7 @@ import java.util.TreeMap;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.datacache.AbstractDataCache;
import org.apache.openjpa.datacache.DataCache;
import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.enhance.Reflection;
@ -1395,15 +1396,24 @@ public class ClassMetaData
}
/**
* The name of the datacache to use for this class, or null if none.
* The name of the datacache to use for this class. If this class is not
* eligible for caching based its annotation or the cache configuration
* null will be returned.
*
* @return The cache name, or null if this type should not be cached.
*/
public String getDataCacheName() {
if (DEFAULT_STRING.equals(_cacheName)) {
if (_super != null)
if (_super != null) {
_cacheName = getPCSuperclassMetaData().getDataCacheName();
else
}
else {
_cacheName = DataCache.NAME_DEFAULT;
}
if(!isCacheable(_cacheName)) {
_cacheName = null;
}
}
return _cacheName;
}
@ -2553,4 +2563,23 @@ public class ClassMetaData
public void setAbstract(boolean flag) {
_abstract = flag;
}
/**
* Determine whether this Type should be included in the DataCache (if one
* is provided) based on the DataCache's configuration.
*
* @return true if the DataCache will accept this type, otherwise false.
*/
private boolean isCacheable(String candidateCacheName) {
boolean rval = true;
DataCache cache =
getRepository().getConfiguration().getDataCacheManagerInstance()
.getDataCache(candidateCacheName);
if (cache != null && (cache instanceof AbstractDataCache)) {
AbstractDataCache adc = (AbstractDataCache) cache;
if (!adc.isCacheableType(getDescribedType().getName()))
rval = false;
}
return rval;
}
}

View File

@ -0,0 +1,71 @@
/*
* 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.datacache;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name="CACHE_EXC_ITEM")
public class Item {
@Id
private int id;
@Version
private int version;
private String name;
private String type;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,87 @@
/*
* 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.datacache;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name="CACHE_EXC_ORDR")
public class Order {
@Id
@GeneratedValue
private int id;
@Version
private int version;
private int quantity;
@OneToOne
private Item item;
@ManyToOne
private Purchase purchase;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public Purchase getPurchase() {
return purchase;
}
public void setPurchase(Purchase purchase) {
this.purchase = purchase;
}
}

View File

@ -0,0 +1,68 @@
/*
* 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.datacache;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Version;
@Entity
@Table(name="CACHE_EXC_PURC")
public class Purchase {
@Id
@GeneratedValue
private int id;
@Version
private int version;
@OneToMany(mappedBy = "purchase", cascade = CascadeType.ALL)
private Collection<Order> orders;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public Collection<Order> getOrders() {
return orders;
}
public void setOrders(Collection<Order> orders) {
this.orders = orders;
}
}

View File

@ -0,0 +1,233 @@
/*
* 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.datacache;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.StoreCache;
import org.apache.openjpa.persistence.test.PersistenceTestCase;
public class TestCacheExclusions extends PersistenceTestCase {
private OpenJPAEntityManagerFactorySPI emf = null;
private static String[] ITEM_NAMES =
{ "Cup", "pen", "pencil", "phone", "laptop", "keyboard", "mouse" };
private static final String _tSep = ";";
Item[] items = new Item[ITEM_NAMES.length];
Order o1, o2;
Purchase p;
public void populate() {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
int n = 0;
for (String s : ITEM_NAMES) {
items[n] = new Item();
items[n].setName(s);
items[n].setId(n);
em.persist(items[n++]);
}
p = new Purchase();
p.setOrders(new ArrayList<Order>());
o1 = new Order();
o1.setItem(em.find(Item.class, 1));
o1.setQuantity(2);
o1.setPurchase(p);
p.getOrders().add(o1);
o2 = new Order();
o2.setItem(em.find(Item.class, 4));
o2.setQuantity(23);
o2.setPurchase(p);
p.getOrders().add(o2);
em.persist(p);
em.getTransaction().commit();
em.close();
}
public void tearDown() throws Exception {
if (emf != null) {
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
for (ClassMapping mapping : ((ClassMapping[]) emf
.getConfiguration().getMetaDataRepositoryInstance()
.getMetaDatas())) {
Query q =
em.createNativeQuery("DROP TABLE "
+ mapping.getTable().getName());
q.executeUpdate();
}
em.getTransaction().commit();
em.close();
emf.close();
}
emf = null;
super.tearDown();
}
public void testCacheAll() {
getEntityManagerFactoryCacheSettings(null, null);
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, true, true, true);
}
public void testCacheItems() {
getEntityManagerFactoryCacheSettings(new Class[] { Item.class }, null);
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, false, false, true);
}
public void testCacheItemsAndPurchases() {
getEntityManagerFactoryCacheSettings(new Class[] { Item.class,
Purchase.class }, null);
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, true, false, true);
}
public void testCacheItemsAndOrders() {
getEntityManagerFactoryCacheSettings(new Class[] { Item.class,
Order.class }, null);
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, false, true, true);
}
public void testCachePurchasesAndOrders() {
getEntityManagerFactoryCacheSettings(new Class[] { Purchase.class,
Order.class }, null);
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, true, true, false);
}
public void testExcludePurchases() {
getEntityManagerFactoryCacheSettings(null,
new Class[] { Purchase.class });
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, false, true, true);
}
public void testExcludeOrders() {
getEntityManagerFactoryCacheSettings(null, new Class[] { Order.class });
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, true, false, true);
}
public void testExcludeItems() {
getEntityManagerFactoryCacheSettings(null, new Class[] { Item.class });
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, true, true, false);
}
public void testExcludeOrdersAndPurchases() {
getEntityManagerFactoryCacheSettings(null, new Class[] { Order.class,
Purchase.class });
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, false, false, true);
}
public void testIncludePurchaseItemExcludePurchase() {
getEntityManagerFactoryCacheSettings(new Class[] { Purchase.class,
Item.class }, new Class[] { Purchase.class });
populate();
StoreCache cache = emf.getStoreCache();
assertCacheContents(cache, false, false, true);
}
public OpenJPAEntityManagerFactorySPI getEntityManagerFactoryCacheSettings(
Class<?>[] includedTypes, Class<?>[] excludedTypes) {
StringBuilder includes = new StringBuilder();
if (includedTypes != null && includedTypes.length > 0) {
includes.append("Types=");
for (Class<?> c : includedTypes) {
includes.append(c.getName());
includes.append(_tSep);
}
includes.setLength(includes.length() - 1); // remove last semicolon
}
StringBuilder excludes = new StringBuilder();
if (excludedTypes != null && excludedTypes.length > 0) {
excludes.append("ExcludedTypes=");
for (Class<?> c : excludedTypes) {
excludes.append(c.getName());
excludes.append(_tSep);
}
excludes.setLength(excludes.length() - 1); // remove last semicolon
}
StringBuilder dataCacheSettings = new StringBuilder();
dataCacheSettings.append("true");
if (includes.length() > 0 || excludes.length() > 0) {
dataCacheSettings.append("(");
dataCacheSettings.append(includes);
if (includes.length() > 0 && excludes.length() > 0) {
dataCacheSettings.append(",");
}
dataCacheSettings.append(excludes);
dataCacheSettings.append(")");
}
Map<String, String> props = new HashMap<String, String>();
props.put("openjpa.DataCache", dataCacheSettings.toString());
props.put("openjpa.RemoteCommitProvider", "sjvm");
props.put("openjpa.MetaDataFactory", "jpa(Types="
+ Item.class.getName() + _tSep + Purchase.class.getName() + _tSep
+ Order.class.getName() + ")");
emf =
(OpenJPAEntityManagerFactorySPI) javax.persistence.Persistence
.createEntityManagerFactory("test", props);
return emf;
}
public void assertCacheContents(StoreCache cache, boolean expectPurchase,
boolean expectOrders, boolean expectItems) {
assertEquals("Expected purchases to " + (expectPurchase ? "" : "not ")
+ "exist in the cache", expectPurchase, cache.contains(
Purchase.class, p.getId()));
assertEquals("Expected Orders to " + (expectOrders ? "" : "not ")
+ "exist in the cache", expectOrders, cache.contains(Order.class,
o1.getId()));
assertEquals("Expected Orders to " + (expectOrders ? "" : "not ")
+ "exist in the cache", expectOrders, cache.contains(Order.class,
o2.getId()));
for (int i = 0; i < ITEM_NAMES.length; i++) {
assertEquals("Expected Items to " + (expectItems ? "" : "not ")
+ "exist in the cache", expectItems, cache.contains(Item.class,
items[i].getId()));
}
}
}