- * When a findUnique query is used with this property as the sole expression
+ * By default query caching is disabled as the query cache invalidates
+ * frequently and so it is typically used for specific bean types and cases.
+ *
+ */
+ boolean enableQueryCache() default false;
+
+ /**
+ * Set this to false to disable the use of bean cache.
+ *
+ * By default bean caching is expected so this defaults to true. We might
+ * set this to false on a bean type that we want to use query caching but no
+ * bean caching (and this is expected to be a rare case).
+ *
+ */
+ boolean enableBeanCache() default true;
+
+ /**
+ * Specify the property that is a natural unique identifier for the bean.
+ *
+ * When a findUnique() query is used with this property as the sole expression
* then there will be a lookup into the L2 natural key cache.
*
*/
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCache.java b/src/main/java/com/avaje/ebean/cache/ServerCache.java
index 195446c20..e3c64a326 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCache.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCache.java
@@ -1,7 +1,5 @@
package com.avaje.ebean.cache;
-import com.avaje.ebean.EbeanServer;
-
/**
* Represents part of the "L2" server side cache.
*
@@ -17,27 +15,6 @@ import com.avaje.ebean.EbeanServer;
*/
public interface ServerCache {
- /**
- * Just after a cache is created this init method is called. This is so that a
- * cache implementation can make use of the BackgroundExecutor service to
- * trim/cleanup itself or use the EbeanServer to populate itself.
- *
- * This method is called after the cache is constructed but before the cache
- * is made available for use.
- *
- */
- void init(EbeanServer ebeanServer);
-
- /**
- * Return the configuration options for this cache.
- */
- ServerCacheOptions getOptions();
-
- /**
- * Update the configuration options for this cache.
- */
- void setOptions(ServerCacheOptions options);
-
/**
* Return the value given the key.
*/
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java b/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java
index 4c913a729..01310c4ee 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCacheFactory.java
@@ -1,23 +1,10 @@
package com.avaje.ebean.cache;
-import com.avaje.ebean.EbeanServer;
-
/**
* Defines method for constructing caches for beans and queries.
*/
public interface ServerCacheFactory {
- /**
- * Just after the ServerCacheFactory is constructed this method is called
- * passing the EbeanServer.
- *
- * This is so that a cache implementation can utilise the EbeanServer to
- * populate itself or use the BackgroundExecutor service to schedule periodic
- * cache trimming/cleanup.
- *
- */
- void init(EbeanServer ebeanServer);
-
/**
* Create the cache for the given type with options.
*/
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java b/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java
index 3e08718c2..50bcffceb 100644
--- a/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java
+++ b/src/main/java/com/avaje/ebean/cache/ServerCacheManager.java
@@ -1,25 +1,10 @@
package com.avaje.ebean.cache;
-import com.avaje.ebean.EbeanServer;
-
/**
* The cache service for server side caching of beans and query results.
*/
public interface ServerCacheManager {
- /**
- * This method is called just after the construction of the
- * ServerCacheManager.
- *
- * The EbeanServer is provided so that cache implementations can make use of
- * EbeanServer and BackgroundExecutor for automatically populating and
- * background trimming of the cache.
- *
- */
- void init(EbeanServer server);
-
- void setCaching(Class> beanType, boolean useCache);
-
/**
* Return true if there is an active bean cache for this type of bean.
*/
@@ -35,6 +20,9 @@ public interface ServerCacheManager {
*/
ServerCache getBeanCache(Class> beanType);
+ /**
+ * Return the cache for associated many properties of a bean type.
+ */
ServerCache getCollectionIdsCache(Class> beanType, String propertyName);
/**
diff --git a/src/main/java/com/avaje/ebean/cache/ServerCachePlugin.java b/src/main/java/com/avaje/ebean/cache/ServerCachePlugin.java
new file mode 100644
index 000000000..2fe635d1c
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/cache/ServerCachePlugin.java
@@ -0,0 +1,15 @@
+package com.avaje.ebean.cache;
+
+import com.avaje.ebean.BackgroundExecutor;
+import com.avaje.ebean.config.ServerConfig;
+
+/**
+ * The plugin interface that creates a ServerCacheFactory.
+ */
+public interface ServerCachePlugin {
+
+ /**
+ * Create the ServerCacheFactory given the server config and background executor service.
+ */
+ ServerCacheFactory create(ServerConfig config, BackgroundExecutor executor);
+}
diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java
index f1c12a2e7..f3d4ab5c9 100644
--- a/src/main/java/com/avaje/ebean/config/ServerConfig.java
+++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java
@@ -5,6 +5,7 @@ import com.avaje.ebean.PersistenceContextScope;
import com.avaje.ebean.annotation.Encrypted;
import com.avaje.ebean.cache.ServerCacheFactory;
import com.avaje.ebean.cache.ServerCacheManager;
+import com.avaje.ebean.cache.ServerCachePlugin;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbEncrypt;
import com.avaje.ebean.event.BeanFindController;
@@ -356,7 +357,7 @@ public class ServerConfig {
private DbEncrypt dbEncrypt;
- private ServerCacheFactory serverCacheFactory;
+ private ServerCachePlugin serverCachePlugin;
private ServerCacheManager serverCacheManager;
@@ -938,17 +939,17 @@ public class ServerConfig {
}
/**
- * Return the ServerCacheFactory.
+ * Return the ServerCachePlugin.
*/
- public ServerCacheFactory getServerCacheFactory() {
- return serverCacheFactory;
+ public ServerCachePlugin getServerCachePlugin() {
+ return serverCachePlugin;
}
/**
- * Set the ServerCacheFactory to use.
+ * Set the ServerCachePlugin to use.
*/
- public void setServerCacheFactory(ServerCacheFactory serverCacheFactory) {
- this.serverCacheFactory = serverCacheFactory;
+ public void setServerCachePlugin(ServerCachePlugin serverCachePlugin) {
+ this.serverCachePlugin = serverCachePlugin;
}
/**
@@ -2352,7 +2353,7 @@ public class ServerConfig {
encryptDeployManager = createInstance(p, EncryptDeployManager.class, "encryptDeployManager", encryptDeployManager);
encryptor = createInstance(p, Encryptor.class, "encryptor", encryptor);
dbEncrypt = createInstance(p, DbEncrypt.class, "dbEncrypt", dbEncrypt);
- serverCacheFactory = createInstance(p, ServerCacheFactory.class, "serverCacheFactory", serverCacheFactory);
+ serverCachePlugin = createInstance(p, ServerCachePlugin.class, "serverCachePlugin", serverCachePlugin);
serverCacheManager = createInstance(p, ServerCacheManager.class, "serverCacheManager", serverCacheManager);
cacheWarmingDelay = p.getInt("cacheWarmingDelay", cacheWarmingDelay);
classPathReaderClassName = p.get("classpathreader");
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java
index a2966c119..f8f415db1 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/visitor/VisitAllUsing.java
@@ -150,8 +150,8 @@ public class VisitAllUsing {
}
public void visit(InheritInfo inheritInfo) {
- BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
- for (int i = 0; i desc, EntityBean bean, CachedBeanData cacheBeanData) {
+ public static void load(BeanDescriptor> desc, EntityBean bean, CachedBeanData cacheBeanData, PersistenceContext context) {
EntityBeanIntercept ebi = bean._ebean_getIntercept();
BeanProperty idProperty = desc.getIdProperty();
if (idProperty != null) {
// load the id property
- loadProperty(bean, cacheBeanData, ebi, idProperty);
+ loadProperty(bean, cacheBeanData, ebi, idProperty, context);
}
// load the non-many properties
BeanProperty[] props = desc.propertiesNonMany();
for (int i = 0; i < props.length; i++) {
- loadProperty(bean, cacheBeanData, ebi, props[i]);
+ loadProperty(bean, cacheBeanData, ebi, props[i], context);
}
BeanPropertyAssocMany>[] many = desc.propertiesMany();
@@ -33,12 +34,12 @@ public class CachedBeanDataToBean {
ebi.setLoadedLazy();
}
- private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop) {
+ private static void loadProperty(EntityBean bean, CachedBeanData cacheBeanData, EntityBeanIntercept ebi, BeanProperty prop, PersistenceContext context) {
if (cacheBeanData.isLoaded(prop.getName())) {
if (!ebi.isLoadedProperty(prop.getPropertyIndex())) {
Object value = cacheBeanData.getData(prop.getName());
- prop.setCacheDataValue(bean, value);
+ prop.setCacheDataValue(bean, value, context);
}
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
index 9269616f0..d7db64a10 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCache.java
@@ -107,15 +107,12 @@ public class DefaultServerCache implements ServerCache {
return 0;
}
- @Override
- public void init(EbeanServer server) {
+ public void periodicTrim(BackgroundExecutor executor) {
EvictionRunnable trim = new EvictionRunnable();
// default to trimming the cache every 60 seconds
long trimFreqSecs = (trimFrequency == 0) ? 60 : trimFrequency;
-
- BackgroundExecutor executor = server.getBackgroundExecutor();
executor.executePeriodically(trim, trimFreqSecs, TimeUnit.SECONDS);
}
@@ -176,33 +173,6 @@ public class DefaultServerCache implements ServerCache {
}
}
- /**
- * Return the options controlling the cache.
- */
- @Override
- public ServerCacheOptions getOptions() {
- synchronized (monitor) {
- ServerCacheOptions options = new ServerCacheOptions();
- options.setMaxIdleSecs(maxIdleSecs);
- options.setMaxSize(maxSize);
- options.setMaxSecsToLive(maxSecsToLive);
- options.setTrimFrequency(trimFrequency);
- return options;
- }
- }
-
- /**
- * Set the options controlling the cache
- */
- @Override
- public void setOptions(ServerCacheOptions options) {
- synchronized (monitor) {
- maxIdleSecs = options.getMaxIdleSecs();
- maxSize = options.getMaxSize();
- maxSecsToLive = options.getMaxSecsToLive();
- }
- }
-
/**
* Return the name of the cache.
*/
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheFactory.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheFactory.java
index 62c22abbe..a17eb0b88 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheFactory.java
@@ -1,6 +1,6 @@
package com.avaje.ebeaninternal.server.cache;
-import com.avaje.ebean.EbeanServer;
+import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.cache.ServerCache;
import com.avaje.ebean.cache.ServerCacheFactory;
import com.avaje.ebean.cache.ServerCacheOptions;
@@ -10,18 +10,30 @@ import com.avaje.ebean.cache.ServerCacheType;
/**
* Default implementation of ServerCacheFactory.
*/
-public class DefaultServerCacheFactory implements ServerCacheFactory {
+class DefaultServerCacheFactory implements ServerCacheFactory {
- private EbeanServer ebeanServer;
+ private final BackgroundExecutor executor;
- public void init(EbeanServer ebeanServer) {
- this.ebeanServer = ebeanServer;
+ /**
+ * Construct when l2 cache is disabled.
+ */
+ public DefaultServerCacheFactory() {
+ this.executor = null;
+ }
+
+ /**
+ * Construct with executor service.
+ */
+ public DefaultServerCacheFactory(BackgroundExecutor executor) {
+ this.executor = executor;
}
public ServerCache createCache(ServerCacheType type, String cacheKey, ServerCacheOptions cacheOptions) {
- ServerCache cache = new DefaultServerCache(cacheKey, cacheOptions);
- cache.init(ebeanServer);
+ DefaultServerCache cache = new DefaultServerCache(cacheKey, cacheOptions);
+ if (executor != null) {
+ cache.periodicTrim(executor);
+ }
return cache;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheManager.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheManager.java
index 93865ac9e..f8abeb657 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCacheManager.java
@@ -1,12 +1,10 @@
package com.avaje.ebeaninternal.server.cache;
-import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.cache.ServerCache;
import com.avaje.ebean.cache.ServerCacheFactory;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.cache.ServerCacheOptions;
import com.avaje.ebean.cache.ServerCacheType;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
/**
@@ -22,15 +20,10 @@ public class DefaultServerCacheManager implements ServerCacheManager {
private final DefaultCacheHolder collectionIdsCache;
- private final ServerCacheFactory cacheFactory;
-
- private SpiEbeanServer ebeanServer;
-
/**
* Create with a cache factory and default cache options.
*/
public DefaultServerCacheManager(ServerCacheFactory cacheFactory, ServerCacheOptions defaultBeanOptions, ServerCacheOptions defaultQueryOptions) {
- this.cacheFactory = cacheFactory;
this.beanCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
this.queryCache = new DefaultCacheHolder(cacheFactory, defaultQueryOptions);
this.naturalKeyCache = new DefaultCacheHolder(cacheFactory, defaultBeanOptions);
@@ -44,18 +37,6 @@ public class DefaultServerCacheManager implements ServerCacheManager {
this(new DefaultServerCacheFactory(), new ServerCacheOptions(), new ServerCacheOptions());
}
- public void init(EbeanServer server) {
- cacheFactory.init(server);
- this.ebeanServer = (SpiEbeanServer) server;
- }
-
- /**
- * Set bean caching on or off for a given bean type.
- */
- public void setCaching(Class> beanType, boolean useCache) {
- ebeanServer.getBeanDescriptor(beanType).setUseCache(useCache);
- }
-
/**
* Clear both the bean cache and the query cache for a
* given bean type.
diff --git a/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCachePlugin.java b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCachePlugin.java
new file mode 100644
index 000000000..9432056ac
--- /dev/null
+++ b/src/main/java/com/avaje/ebeaninternal/server/cache/DefaultServerCachePlugin.java
@@ -0,0 +1,20 @@
+package com.avaje.ebeaninternal.server.cache;
+
+import com.avaje.ebean.BackgroundExecutor;
+import com.avaje.ebean.cache.ServerCacheFactory;
+import com.avaje.ebean.cache.ServerCachePlugin;
+import com.avaje.ebean.config.ServerConfig;
+
+/**
+ * Default implementation of ServerCachePlugin.
+ */
+public class DefaultServerCachePlugin implements ServerCachePlugin {
+
+ /**
+ * Creates the default ServerCacheFactory.
+ */
+ @Override
+ public ServerCacheFactory create(ServerConfig config, BackgroundExecutor executor) {
+ return new DefaultServerCacheFactory(executor);
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/CacheOptions.java b/src/main/java/com/avaje/ebeaninternal/server/core/CacheOptions.java
index 0ca7641aa..89477900d 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/CacheOptions.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/CacheOptions.java
@@ -1,111 +1,67 @@
package com.avaje.ebeaninternal.server.core;
+import com.avaje.ebean.annotation.Cache;
+
/**
* Options for controlling cache behaviour for a given type.
*/
public class CacheOptions {
- private boolean useCache;
-
- private boolean readOnly;
-
- private String naturalKey;
-
- private int maxIdleSecs;
-
- private long maxSecsToLive;
-
/**
- * Construct with options.
+ * Instance when no caching is used.
*/
- public CacheOptions() {
+ public static CacheOptions NO_CACHING = new CacheOptions();
+
+ private final boolean enableBeanCache;
+ private final boolean enableQueryCache;
+ private final boolean readOnly;
+ private final String naturalKey;
+
+ /**
+ * Construct for no caching.
+ */
+ private CacheOptions() {
+ enableBeanCache = false;
+ enableQueryCache = false;
+ readOnly = false;
+ naturalKey = null;
}
/**
- * Return true if this should use a cache for lazy loading.
+ * Construct with cache annotation.
*/
- public boolean isUseCache() {
- return useCache;
+ public CacheOptions(Cache cache, String naturalKey) {
+ enableBeanCache = cache.enableBeanCache();
+ enableQueryCache = cache.enableQueryCache();
+ readOnly = cache.readOnly();
+ this.naturalKey = naturalKey;
}
/**
- * Set whether to use the bean cache for the associated type.
+ * Return true if bean caching is enabled.
*/
- public void setUseCache(boolean useCache) {
- this.useCache = useCache;
+ public boolean isEnableBeanCache() {
+ return enableBeanCache;
}
/**
- * Return the readOnly default setting.
+ * Return true if query caching is enabled.
+ */
+ public boolean isEnableQueryCache() {
+ return enableQueryCache;
+ }
+
+ /**
+ * Return true if bean cache hits default to read only.
*/
public boolean isReadOnly() {
return readOnly;
}
/**
- * Set read Only default setting.
- */
- public void setReadOnly(boolean readOnly) {
- this.readOnly = readOnly;
- }
-
- /**
- * Return true if a natural key is set.
- */
- public boolean isUseNaturalKeyCache() {
- return naturalKey != null;
- }
-
- /**
- * Return the natural key property.
+ * Return the natural key property name.
*/
public String getNaturalKey() {
return naturalKey;
}
-
- /**
- * Set the natural key property.
- */
- public void setNaturalKey(String naturalKey) {
- if (naturalKey != null && naturalKey.length() != 0) {
- this.naturalKey = naturalKey.trim();
- }
- }
-
- /**
- * Return the max age of entries in seconds.
- */
- public long getMaxSecsToLive() {
- return maxSecsToLive;
- }
-
- /**
- * Set the max age of entries in seconds.
- */
- public void setMaxSecsToLive(long maxSecsToLive) {
- this.maxSecsToLive = maxSecsToLive;
- }
-
- /**
- * Set the max idle seconds.
- */
- public void setMaxIdleSecs(int maxIdleSecs) {
- this.maxIdleSecs = maxIdleSecs;
- }
-
- /**
- * Return the max idle seconds.
- */
- public int getMaxIdleSecs() {
- return maxIdleSecs;
- }
-
- /**
- * Return true if the entry exceeds the maxIdleSecs or maxSecsToLive.
- */
- public boolean isTooOldInMillis(long ageMillis) {
- long secs = ageMillis / 1000;
- return (maxIdleSecs > 0 && secs > maxIdleSecs) || (maxSecsToLive > 0 && secs > maxSecsToLive);
- }
-
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
index a2b13a15d..ed319ff8a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultBeanLoader.java
@@ -270,15 +270,15 @@ public class DefaultBeanLoader {
boolean draft = desc.isDraftInstance(bean);
if (embeddedOwnerIndex == -1) {
- if (!draft && SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
- // lazy loading and the bean cache is active
- if (desc.cacheBeanLoad(bean, ebi, id)) {
- return;
- }
- }
if (desc.lazyLoadMany(ebi)) {
return;
}
+ if (!draft && SpiQuery.Mode.LAZYLOAD_BEAN.equals(mode) && desc.isBeanCaching()) {
+ // lazy loading and the bean cache is active
+ if (desc.cacheBeanLoad(bean, ebi, id, pc)) {
+ return;
+ }
+ }
}
SpiQuery> query = (SpiQuery>) server.createQuery(desc.getBeanType());
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
index 4dc2fa465..d757568d2 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
@@ -1,8 +1,10 @@
package com.avaje.ebeaninternal.server.core;
+import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.cache.ServerCacheFactory;
import com.avaje.ebean.cache.ServerCacheManager;
import com.avaje.ebean.cache.ServerCacheOptions;
+import com.avaje.ebean.cache.ServerCachePlugin;
import com.avaje.ebean.common.SpiContainer;
import com.avaje.ebean.config.ContainerConfig;
import com.avaje.ebean.config.PropertyMap;
@@ -12,7 +14,7 @@ import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.DbOffline;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.server.cache.DefaultServerCacheFactory;
+import com.avaje.ebeaninternal.server.cache.DefaultServerCachePlugin;
import com.avaje.ebeaninternal.server.cache.DefaultServerCacheManager;
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
@@ -108,19 +110,15 @@ public class DefaultContainer implements SpiContainer {
// inform the NamingConvention of the associated DatabasePlatform
serverConfig.getNamingConvention().setDatabasePlatform(serverConfig.getDatabasePlatform());
- ServerCacheManager cacheManager = getCacheManager(online, serverConfig);
+ // executor and l2 caching service setup early (used during server construction)
+ SpiBackgroundExecutor executor = createBackgroundExecutor(serverConfig);
+ ServerCacheManager cacheManager = getCacheManager(online, serverConfig, executor);
- SpiBackgroundExecutor bgExecutor = createBackgroundExecutor(serverConfig);
-
- XmlConfigLoader xmlConfigLoader = new XmlConfigLoader(null);
- XmlConfig xmlConfig = xmlConfigLoader.load();
-
- InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, bgExecutor, serverConfig, bootupClasses);
+ XmlConfig xmlConfig = new XmlConfigLoader(null).load();
+ InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, executor, serverConfig, bootupClasses);
DefaultServer server = new DefaultServer(c, cacheManager);
- cacheManager.init(server);
-
// generate and run DDL if required
// if there are any other tasks requiring action in their plugins, do them as well
if (!DbOffline.isRunningMigration()) {
@@ -147,7 +145,7 @@ public class DefaultContainer implements SpiContainer {
/**
* Create and return the CacheManager.
*/
- private ServerCacheManager getCacheManager(boolean online, ServerConfig serverConfig) {
+ private ServerCacheManager getCacheManager(boolean online, ServerConfig serverConfig, BackgroundExecutor executor) {
if (!online || serverConfig.isDisableL2Cache()) {
// use local only L2 cache implementation as placeholder
@@ -171,21 +169,22 @@ public class DefaultContainer implements SpiContainer {
queryOptions.setMaxIdleSecs(serverConfig.getQueryCacheMaxIdleTime());
queryOptions.setMaxSecsToLive(serverConfig.getQueryCacheMaxTimeToLive());
- ServerCacheFactory cacheFactory = serverConfig.getServerCacheFactory();
- if (cacheFactory == null) {
- ServiceLoader cacheFactories = ServiceLoader.load(ServerCacheFactory.class);
- Iterator iterator = cacheFactories.iterator();
+ ServerCachePlugin plugin = serverConfig.getServerCachePlugin();
+ if (plugin == null) {
+ ServiceLoader cacheFactories = ServiceLoader.load(ServerCachePlugin.class);
+ Iterator iterator = cacheFactories.iterator();
if (iterator.hasNext()) {
// use the cacheFactory (via classpath service loader)
- cacheFactory = iterator.next();
- logger.debug("using ServerCacheFactory {}", cacheFactory.getClass());
+ plugin = iterator.next();
+ logger.debug("using ServerCacheFactory {}", plugin.getClass());
} else {
// use the built in default
- cacheFactory = new DefaultServerCacheFactory();
+ plugin = new DefaultServerCachePlugin();
}
}
- return new DefaultServerCacheManager(cacheFactory, beanOptions, queryOptions);
+ ServerCacheFactory factory = plugin.create(serverConfig, executor);
+ return new DefaultServerCacheManager(factory, beanOptions, queryOptions);
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
index f067a8350..b14c09953 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultServer.java
@@ -335,11 +335,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (encryptKeyManager != null) {
encryptKeyManager.initialise();
}
- List> list = beanDescriptorManager.getBeanDescriptorList();
- for (int i = 0; i < list.size(); i++) {
- list.get(i).cacheInitialise();
- }
-
}
/**
@@ -1026,7 +1021,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
* Try to get the object out of the persistence context.
*/
@SuppressWarnings("unchecked")
- private T findIdCheckPersistenceContextAndCache(Transaction transaction, SpiQuery query) {
+ private T findIdCheckPersistenceContextAndCache(Transaction transaction, SpiQuery query, Object id) {
SpiTransaction t = (SpiTransaction) transaction;
if (t == null) {
@@ -1034,13 +1029,14 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
BeanDescriptor desc = query.getBeanDescriptor();
+ id = desc.convertId(id);
PersistenceContext pc = null;
if (t != null && useTransactionPersistenceContext(query)) {
// first look in the transaction scoped persistence context
pc = t.getPersistenceContext();
if (pc != null) {
- WithOption o = desc.contextGetWithOption(pc, query.getId());
+ WithOption o = desc.contextGetWithOption(pc, id);
if (o != null) {
if (o.isDeleted()) {
// Bean was previously deleted in the same transaction / persistence context
@@ -1057,7 +1053,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
}
// Hit the L2 bean cache
- return desc.cacheBeanGet(query, pc);
+ return desc.cacheBeanGet(id, query.isReadOnly(), pc);
}
/**
@@ -1083,7 +1079,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
if (SpiQuery.Mode.NORMAL.equals(spiQuery.getMode()) && !spiQuery.isLoadBeanCache()) {
// See if we can skip doing the fetch completely by getting the bean from the
// persistence context or the bean cache
- T bean = findIdCheckPersistenceContextAndCache(t, spiQuery);
+ T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, spiQuery.getId());
if (bean != null) {
return bean;
}
@@ -1104,19 +1100,21 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
public T findUnique(Query query, Transaction t) {
- // actually a find by Id type of query...
- // ... perhaps with joins and cache hints
Object id = query.getId();
if (id != null) {
+ // actually a find by Id query
return findId(query, t);
}
SpiQuery spiQuery = (SpiQuery) query;
BeanDescriptor desc = spiQuery.getBeanDescriptor();
- T bean = desc.cacheNaturalKeyLookup(spiQuery, (SpiTransaction) t);
- if (bean != null) {
- return bean;
+ id = desc.cacheNaturalKeyIdLookup(spiQuery);
+ if (id != null) {
+ T bean = findIdCheckPersistenceContextAndCache(t, spiQuery, id);
+ if (bean != null) {
+ return bean;
+ }
}
// a query that is expected to return either 0 or 1 rows
@@ -2025,16 +2023,6 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return beanDescriptorManager.getBeanDescriptorByClassName(beanClassName);
}
- @Override
- public boolean initQueryCache(String key) {
- BeanDescriptor> desc = getBeanDescriptorById(key);
- if (desc != null) {
- desc.queryCacheInit();
- return true;
- }
- return false;
- }
-
/**
* Another server in the cluster sent this event so that we can inform local
* BeanListeners of inserts updates and deletes that occurred remotely (on
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
index 7b63e68cc..eb57cef1b 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/PersistRequestBean.java
@@ -548,7 +548,7 @@ public final class PersistRequestBean extends PersistRequest implements BeanP
* Create and return a new reference bean matching this beans Id value.
*/
public T createReference() {
- return beanDescriptor.createReference(Boolean.FALSE, getBeanId());
+ return beanDescriptor.createReference(Boolean.FALSE, getBeanId(), null);
}
/**
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java
index ead82f1e6..6c2634f65 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/AssocOneHelpRefInherit.java
@@ -46,7 +46,7 @@ class AssocOneHelpRefInherit extends AssocOneHelp {
// check transaction context to see if it already exists
PersistenceContext pc = ctx.getPersistenceContext();
- BeanDescriptor> desc = rowInheritInfo.getBeanDescriptor();
+ BeanDescriptor> desc = rowInheritInfo.desc();
Object existing = desc.contextGet(pc, id);
if (existing != null) {
return existing;
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
index 742e7088d..7d7234451 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanDescriptor.java
@@ -39,7 +39,6 @@ import com.avaje.ebeaninternal.api.CQueryPlanKey;
import com.avaje.ebeaninternal.api.LoadContext;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.api.SpiQuery;
-import com.avaje.ebeaninternal.api.SpiTransaction;
import com.avaje.ebeaninternal.api.SpiUpdatePlan;
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
import com.avaje.ebeaninternal.server.cache.CacheChangeSet;
@@ -723,7 +722,7 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType {
propertiesMany[i].initialisePostTarget();
}
if (inheritInfo != null && !inheritInfo.isRoot()) {
- docStoreAdapter = (DocStoreBeanAdapter)inheritInfo.getRoot().getBeanDescriptor().docStoreAdapter();
+ docStoreAdapter = (DocStoreBeanAdapter)inheritInfo.getRoot().desc().docStoreAdapter();
}
docMapping = docStoreAdapter.createDocMapping();
docStoreAdapter.registerPaths();
@@ -803,13 +802,6 @@ public class BeanDescriptor implements MetaBeanInfo, BeanType {
return new BeanChange(getBaseTable(), id, changeType, values);
}
- /**
- * Initialise the cache once the server has started.
- */
- public void cacheInitialise() {
- cacheHelp.initialise();
- }
-
public SqlUpdate deleteById(Object id, List
*/
- public void setCacheDataValue(EntityBean bean, Object cacheData) {
+ public void setCacheDataValue(EntityBean bean, Object cacheData, PersistenceContext context) {
if (cacheData instanceof String) {
// parse back from string to support optimisation of java object serialisation
cacheData = scalarType.parse((String)cacheData);
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
index fc364ac21..9fd52d7c3 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocMany.java
@@ -1022,7 +1022,7 @@ public class BeanPropertyAssocMany extends BeanPropertyAssoc {
if (isManyToMany()) {
if (liveBean == null) {
// add new relationship (Map not allowed here)
- liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, id));
+ liveVal.addBean(targetDescriptor.createReference(Boolean.FALSE, id, null));
}
} else {
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
index d299cb57e..d79ddef60 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/BeanPropertyAssocOne.java
@@ -6,6 +6,7 @@ import com.avaje.ebean.SqlUpdate;
import com.avaje.ebean.Transaction;
import com.avaje.ebean.ValuePair;
import com.avaje.ebean.bean.EntityBean;
+import com.avaje.ebean.bean.PersistenceContext;
import com.avaje.ebeaninternal.server.cache.CacheChangeSet;
import com.avaje.ebeaninternal.server.cache.CachedBeanData;
import com.avaje.ebeaninternal.server.core.DefaultSqlUpdate;
@@ -399,17 +400,22 @@ public class BeanPropertyAssocOne extends BeanPropertyAssoc {
}
@Override
- public void setCacheDataValue(EntityBean bean, Object cacheData) {
+ public void setCacheDataValue(EntityBean bean, Object cacheData, PersistenceContext context) {
if (cacheData == null) {
setValue(bean, null);
} else {
if (embedded) {
- setValue(bean, targetDescriptor.cacheEmbeddedBeanLoad((CachedBeanData) cacheData));
+ setValue(bean, targetDescriptor.cacheEmbeddedBeanLoad((CachedBeanData) cacheData, context));
} else {
if (cacheData instanceof String) {
cacheData = targetDescriptor.getIdProperty().scalarType.parse((String)cacheData);
}
- setValue(bean, targetDescriptor.createReference(Boolean.FALSE, cacheData));
+ // cacheData is the id value, maybe already in persistence context
+ Object assocBean = targetDescriptor.contextGet(context, cacheData);
+ if (assocBean == null) {
+ assocBean = targetDescriptor.createReference(Boolean.FALSE, cacheData, context);
+ }
+ setValue(bean, assocBean);
}
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java
index 28ba06a7d..d8433bad6 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/InheritInfo.java
@@ -141,7 +141,7 @@ public class InheritInfo {
/**
* Return the associated BeanDescriptor for this node.
*/
- public BeanDescriptor> getBeanDescriptor() {
+ public BeanDescriptor> desc() {
return descriptor;
}
@@ -161,10 +161,8 @@ public class InheritInfo {
for (int i = 0, x = children.size(); i < x; i++) {
InheritInfo childInfo = children.get(i);
-
// recursively search this child bean descriptor
- prop = childInfo.getBeanDescriptor().findBeanProperty(propertyName);
-
+ prop = childInfo.desc().findBeanProperty(propertyName);
if (prop != null) {
return prop;
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
index fd1e69f85..ffc011528 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/meta/DeployBeanDescriptor.java
@@ -1,5 +1,6 @@
package com.avaje.ebeaninternal.server.deploy.meta;
+import com.avaje.ebean.annotation.Cache;
import com.avaje.ebeaninternal.api.ConcurrencyMode;
import com.avaje.ebean.annotation.DocStore;
import com.avaje.ebean.annotation.DocStoreMode;
@@ -153,7 +154,7 @@ public class DeployBeanDescriptor {
private final List queryAdapters = new ArrayList();
private final List postLoaders = new ArrayList();
- private final CacheOptions cacheOptions = new CacheOptions();
+ private CacheOptions cacheOptions = CacheOptions.NO_CACHING;
/**
* If set overrides the find implementation. Server side only.
@@ -442,6 +443,24 @@ public class DeployBeanDescriptor {
this.inheritInfo = inheritInfo;
}
+ /**
+ * Enable L2 bean and query caching based on Cache annotation.
+ */
+ public void setCache(Cache cache) {
+
+ String naturalKey = null;
+ if (cache.naturalKey().length() > 0) {
+ // find the property and mark as natural key property
+ String propName = cache.naturalKey().trim();
+ DeployBeanProperty beanProperty = getBeanProperty(propName);
+ if (beanProperty != null) {
+ beanProperty.setNaturalKey();
+ naturalKey = propName;
+ }
+ }
+ this.cacheOptions = new CacheOptions(cache, naturalKey);
+ }
+
/**
* Return the cache options.
*/
diff --git a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java
index d1165812d..424c2b39f 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/deploy/parse/AnnotationClass.java
@@ -1,7 +1,6 @@
package com.avaje.ebeaninternal.server.deploy.parse;
-import com.avaje.ebean.annotation.CacheStrategy;
-import com.avaje.ebean.annotation.CacheBeanTuning;
+import com.avaje.ebean.annotation.Cache;
import com.avaje.ebean.annotation.DbComment;
import com.avaje.ebean.annotation.DocStore;
import com.avaje.ebean.annotation.Draftable;
@@ -14,7 +13,6 @@ import com.avaje.ebean.annotation.ReadAudit;
import com.avaje.ebean.annotation.UpdateMode;
import com.avaje.ebean.annotation.View;
import com.avaje.ebean.config.TableName;
-import com.avaje.ebeaninternal.server.core.CacheOptions;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueConstraint;
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
@@ -202,34 +200,9 @@ public class AnnotationClass extends AnnotationParser {
readNamedUpdate(namedUpdate);
}
- CacheStrategy cacheStrategy = cls.getAnnotation(CacheStrategy.class);
- CacheBeanTuning cacheBeanTuning = cls.getAnnotation(CacheBeanTuning.class);
- if (cacheStrategy != null || cacheBeanTuning != null) {
- readCacheStrategy(cacheStrategy, cacheBeanTuning);
- }
- }
-
- private void readCacheStrategy(CacheStrategy cacheStrategy, CacheBeanTuning cacheBeanTuning) {
-
- if (disableL2Cache) {
- return;
- }
- CacheOptions cacheOptions = descriptor.getCacheOptions();
- if (cacheBeanTuning != null) {
- cacheOptions.setMaxSecsToLive(cacheBeanTuning.maxSecsToLive());
- cacheOptions.setMaxIdleSecs(cacheBeanTuning.maxIdleSecs());
- }
- if (cacheStrategy != null) {
- cacheOptions.setUseCache(cacheStrategy.useBeanCache());
- cacheOptions.setReadOnly(cacheStrategy.readOnly());
- if (cacheStrategy.naturalKey().length() > 0) {
- String propName = cacheStrategy.naturalKey().trim();
- DeployBeanProperty beanProperty = descriptor.getBeanProperty(propName);
- if (beanProperty != null) {
- beanProperty.setNaturalKey();
- cacheOptions.setNaturalKey(propName);
- }
- }
+ Cache cache = cls.getAnnotation(Cache.class);
+ if (cache != null && !disableL2Cache) {
+ descriptor.setCache(cache);
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
index 575a1fc02..fe4af3aae 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/loadcontext/DLoadBeanContext.java
@@ -175,7 +175,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
return;
}
- if (context.hitCache && context.desc.cacheBeanLoad(ebi)) {
+ if (context.hitCache && context.desc.cacheBeanLoad(ebi, persistenceContext)) {
// successfully hit the L2 cache so don't invoke DB lazy loading
list.remove(ebi);
return;
@@ -185,7 +185,7 @@ public class DLoadBeanContext extends DLoadBaseContext implements LoadBeanContex
// check each of the beans in the batch to see if they are in the L2 cache.
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
- if (context.desc.cacheBeanLoad(iterator.next())) {
+ if (context.desc.cacheBeanLoad(iterator.next(), persistenceContext)) {
iterator.remove();
}
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
index ff2cd19c4..9bf0a2793 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/persist/DefaultPersister.java
@@ -1352,7 +1352,7 @@ public final class DefaultPersister implements Persister {
// convert into a list of reference objects and perform delete by object
List