mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
Refactor properties bootup, remove GlobalProperties and allow ServerConfig.loadFromProperties()
This commit is contained in:
@@ -15,7 +15,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.annotation.CacheStrategy;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
@@ -155,14 +154,14 @@ public final class Ebean {
|
||||
|
||||
// skipDefaultServer is set by EbeanServerFactory
|
||||
// ... when it is creating the primaryServer
|
||||
if (GlobalProperties.isSkipPrimaryServer()) {
|
||||
if (PrimaryServer.isSkip()) {
|
||||
// primary server being created by EbeanServerFactory
|
||||
// ... so we should not try and create it here
|
||||
logger.debug("GlobalProperties.isSkipPrimaryServer()");
|
||||
logger.debug("PrimaryServer.isSkip()");
|
||||
|
||||
} else {
|
||||
// look to see if there is a default server defined
|
||||
String primaryName = getPrimaryServerName();
|
||||
String primaryName = PrimaryServer.getPrimaryServerName();
|
||||
logger.debug("primaryName:" + primaryName);
|
||||
if (primaryName != null && primaryName.trim().length() > 0) {
|
||||
primaryServer = getWithCreate(primaryName.trim());
|
||||
@@ -170,12 +169,6 @@ public final class Ebean {
|
||||
}
|
||||
}
|
||||
|
||||
private String getPrimaryServerName() {
|
||||
|
||||
String serverName = GlobalProperties.get("ebean.default.datasource", null);
|
||||
return GlobalProperties.get("datasource.default", serverName);
|
||||
}
|
||||
|
||||
private EbeanServer getPrimaryServer() {
|
||||
if (primaryServer == null) {
|
||||
String msg = "The default EbeanServer has not been defined?";
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Creates EbeanServer instances.
|
||||
@@ -27,31 +28,43 @@ import com.avaje.ebean.util.ClassUtil;
|
||||
*/
|
||||
public class EbeanServerFactory {
|
||||
|
||||
private static BootupEbeanManager serverFactory = createServerFactory();
|
||||
|
||||
private static BootupEbeanManager bootupEbeanManager;
|
||||
|
||||
/**
|
||||
* Initialise the container with clustering configuration.
|
||||
*
|
||||
* Call this prior to creating any EbeanServer instances or alternatively set the
|
||||
* ContainerConfig on the ServerConfig when creating the first EbeanServer instance.
|
||||
*/
|
||||
public static synchronized void initialiseContainer(ContainerConfig containerConfig) {
|
||||
getServerFactory(containerConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using ebean.properties to configure the server.
|
||||
*/
|
||||
public static EbeanServer create(String name) {
|
||||
public static synchronized EbeanServer create(String name) {
|
||||
|
||||
EbeanServer server = serverFactory.createServer(name);
|
||||
|
||||
return server;
|
||||
// construct based on loading properties files
|
||||
// and if invoked by Ebean then it handles registration
|
||||
BootupEbeanManager serverFactory = getServerFactory(null);
|
||||
return serverFactory.createServer(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create using the ServerConfig object to configure the server.
|
||||
*/
|
||||
public static EbeanServer create(ServerConfig config) {
|
||||
public static synchronized EbeanServer create(ServerConfig config) {
|
||||
|
||||
if (config.getName() == null) {
|
||||
throw new PersistenceException("The name is null (it is required)");
|
||||
}
|
||||
|
||||
EbeanServer server = serverFactory.createServer(config);
|
||||
EbeanServer server = createInternal(config);
|
||||
|
||||
if (config.isDefaultServer()) {
|
||||
GlobalProperties.setSkipPrimaryServer(true);
|
||||
PrimaryServer.setSkip(true);
|
||||
}
|
||||
if (config.isRegister()) {
|
||||
Ebean.register(server, config.isDefaultServer());
|
||||
@@ -60,13 +73,45 @@ public class EbeanServerFactory {
|
||||
return server;
|
||||
}
|
||||
|
||||
private static BootupEbeanManager createServerFactory() {
|
||||
|
||||
private static EbeanServer createInternal(ServerConfig config) {
|
||||
|
||||
return getServerFactory(config.getContainerConfig()).createServer(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the BootupEbeanManager initialising it if necessary.
|
||||
*
|
||||
* @param containerConfig the configuration controlling clustering communication
|
||||
*/
|
||||
private static BootupEbeanManager getServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
if (bootupEbeanManager != null) {
|
||||
return bootupEbeanManager;
|
||||
}
|
||||
|
||||
if (containerConfig == null) {
|
||||
// effectively load configuration from ebean.properties
|
||||
Properties properties = PrimaryServer.getProperties();
|
||||
containerConfig = new ContainerConfig();
|
||||
containerConfig.loadFromProperties(properties);
|
||||
}
|
||||
bootupEbeanManager = createServerFactory(containerConfig);
|
||||
return bootupEbeanManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the container instance using the configuration.
|
||||
*/
|
||||
private static BootupEbeanManager createServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
String dflt = "com.avaje.ebeaninternal.server.core.DefaultServerFactory";
|
||||
String implClassName = System.getProperty("ebean.serverfactory", dflt);
|
||||
|
||||
try {
|
||||
return (BootupEbeanManager) ClassUtil.newInstance(implClassName);
|
||||
Class<?> cls = Class.forName(implClassName);
|
||||
Constructor<?> constructor = cls.getConstructor(ContainerConfig.class);
|
||||
return (BootupEbeanManager) constructor.newInstance(containerConfig);
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.avaje.ebean;
|
||||
|
||||
import com.avaje.ebean.config.PropertyMap;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Provides singleton state for the default server.
|
||||
* <p/>
|
||||
* Intended for internal use as part of bootup, construction, registration of the default server.
|
||||
*/
|
||||
class PrimaryServer {
|
||||
|
||||
private static Properties globalProperties;
|
||||
|
||||
private static String defaultServerName;
|
||||
|
||||
private static boolean skip;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized void setSkip(boolean skip) {
|
||||
PrimaryServer.skip = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary server.
|
||||
*/
|
||||
static synchronized boolean isSkip() {
|
||||
return skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default server name.
|
||||
*/
|
||||
static synchronized String getPrimaryServerName() {
|
||||
getProperties();
|
||||
return defaultServerName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default configuration Properties.
|
||||
*/
|
||||
static synchronized Properties getProperties() {
|
||||
if (globalProperties == null) {
|
||||
globalProperties = PropertyMap.defaultProperties();
|
||||
}
|
||||
defaultServerName = globalProperties.getProperty("datasource.default");
|
||||
if (defaultServerName == null) {
|
||||
defaultServerName = globalProperties.getProperty("ebean.default.datasource");
|
||||
}
|
||||
return globalProperties;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Provides some base implementation for NamingConventions.
|
||||
*
|
||||
*
|
||||
* @author emcgreal
|
||||
*/
|
||||
public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
@@ -41,7 +41,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
/** Used to trim off extra prefix for M2M. */
|
||||
protected int rhsPrefixLength = 3;
|
||||
|
||||
protected boolean useForeignKeyPrefix = true;
|
||||
protected boolean useForeignKeyPrefix;
|
||||
|
||||
/**
|
||||
* Construct with a sequence format and useForeignKeyPrefix setting.
|
||||
@@ -53,12 +53,12 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
|
||||
/**
|
||||
* Construct with a sequence format.
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* the sequence format
|
||||
*
|
||||
* @param sequenceFormat the sequence format
|
||||
*/
|
||||
public AbstractNamingConvention(String sequenceFormat) {
|
||||
this.sequenceFormat = sequenceFormat;
|
||||
this.useForeignKeyPrefix = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,10 +125,9 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* The format should include "{table}". When generating the sequence name
|
||||
* {table} is replaced with the actual table name.
|
||||
* </p>
|
||||
*
|
||||
* @param sequenceFormat
|
||||
* string containing "{table}" which is replaced with the actual
|
||||
* table name to generate the sequence name.
|
||||
*
|
||||
* @param sequenceFormat string containing "{table}" which is replaced with the actual
|
||||
* table name to generate the sequence name.
|
||||
*/
|
||||
public void setSequenceFormat(String sequenceFormat) {
|
||||
this.sequenceFormat = sequenceFormat;
|
||||
@@ -173,7 +172,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
* This first checks for the @Table annotation and if not present uses the
|
||||
* naming convention to define the table name.
|
||||
* </p>
|
||||
*
|
||||
*
|
||||
* @see #getTableNameFromAnnotation(Class)
|
||||
* @see #getTableNameByConvention(Class)
|
||||
*/
|
||||
@@ -240,8 +239,7 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
if (t != null && !isEmpty(t.name())) {
|
||||
// Note: empty catalog and schema are converted to null
|
||||
// Only need to convert quoted identifiers from annotations
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()),
|
||||
quoteIdentifiers(t.name()));
|
||||
return new TableName(quoteIdentifiers(t.catalog()), quoteIdentifiers(t.schema()), quoteIdentifiers(t.name()));
|
||||
}
|
||||
|
||||
// No annotation
|
||||
@@ -279,4 +277,16 @@ public abstract class AbstractNamingConvention implements NamingConvention {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load settings from properties.
|
||||
*/
|
||||
@Override
|
||||
public void loadFromProperties(PropertiesWrapper properties) {
|
||||
|
||||
useForeignKeyPrefix = properties.getBoolean("namingConvention.useForeignKeyPrefix", useForeignKeyPrefix);
|
||||
sequenceFormat = properties.get("namingConvention.sequenceFormat", sequenceFormat);
|
||||
schema = properties.get("namingConvention.schema", schema);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -155,14 +155,6 @@ public class AutofetchConfig {
|
||||
return logDirectory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the log directory substituting any expressions such as
|
||||
* ${catalina.base} etc.
|
||||
*/
|
||||
public String getLogDirectoryWithEval() {
|
||||
return GlobalProperties.evaluateExpressions(logDirectory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the directory to put the autofetch log in.
|
||||
*/
|
||||
@@ -234,22 +226,20 @@ public class AutofetchConfig {
|
||||
/**
|
||||
* Load the settings from the properties file.
|
||||
*/
|
||||
public void loadSettings(GlobalProperties.PropertySource p) {
|
||||
public void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
logDirectory = p.get("autofetch.logDirectory", null);
|
||||
queryTuning = p.getBoolean("autofetch.querytuning", false);
|
||||
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", false);
|
||||
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", false);
|
||||
logDirectory = p.get("autofetch.logDirectory", logDirectory);
|
||||
queryTuning = p.getBoolean("autofetch.querytuning", queryTuning);
|
||||
queryTuningAddVersion = p.getBoolean("autofetch.queryTuningAddVersion", queryTuningAddVersion);
|
||||
garbageCollectionOnShutdown = p.getBoolean("autofetch.garbageCollectionOnShutdown", garbageCollectionOnShutdown);
|
||||
|
||||
profiling = p.getBoolean("autofetch.profiling", false);
|
||||
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", AutofetchMode.DEFAULT_ONIFEMPTY);
|
||||
profiling = p.getBoolean("autofetch.profiling", profiling);
|
||||
mode = p.getEnum(AutofetchMode.class, "autofetch.implicitmode", mode);
|
||||
|
||||
profilingMin = p.getInt("autofetch.profiling.min", 1);
|
||||
profilingBase = p.getInt("autofetch.profiling.base", 10);
|
||||
profilingMin = p.getInt("autofetch.profiling.min", profilingMin);
|
||||
profilingBase = p.getInt("autofetch.profiling.base", profilingBase);
|
||||
|
||||
String rate = p.get("autofetch.profiling.rate", "0.05");
|
||||
profilingRate = Double.parseDouble(rate);
|
||||
|
||||
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", 60);
|
||||
profilingRate = p.getDouble("autofetch.profiling.rate", profilingRate);
|
||||
profileUpdateFrequency = p.getInt("autofetch.profiling.updatefrequency", profileUpdateFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties.PropertySource;
|
||||
|
||||
/**
|
||||
* Helper to read server specific properties from ebean.properties.
|
||||
*/
|
||||
class ConfigPropertyMap implements PropertySource {
|
||||
|
||||
private final String serverName;
|
||||
|
||||
public ConfigPropertyMap(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
public String get(String key, String defaultValue) {
|
||||
String namedKey = "ebean." + serverName + "." + key;
|
||||
String inheritKey = "ebean." + key;
|
||||
String value = GlobalProperties.get(namedKey, null);
|
||||
if (value == null) {
|
||||
value = GlobalProperties.get(inheritKey, null);
|
||||
}
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public int getInt(String key, int defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,464 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Configuration for the container that holds the EbeanServer instances.
|
||||
* <p>
|
||||
* Provides configuration for cluster communication (if clustering is used). The cluster communication is
|
||||
* used to invalidate appropriate parts of the L2 cache across the cluster.
|
||||
*/
|
||||
public class ContainerConfig {
|
||||
|
||||
/**
|
||||
* Communication mode used for clustering.
|
||||
*/
|
||||
public enum ClusterMode {
|
||||
|
||||
/**
|
||||
* No clustering.
|
||||
*/
|
||||
NONE,
|
||||
|
||||
/**
|
||||
* Use Multicast networking for cluster wide communication.
|
||||
*/
|
||||
MULTICAST,
|
||||
|
||||
/**
|
||||
* Use TCP Sockets for cluster wide communication.
|
||||
*/
|
||||
SOCKET
|
||||
}
|
||||
|
||||
/**
|
||||
* The cluster mode to use.
|
||||
*/
|
||||
ClusterMode mode = ClusterMode.NONE;
|
||||
|
||||
/**
|
||||
* Configuration if using TCP sockets for clustering communication.
|
||||
*/
|
||||
SocketConfig socketConfig = new SocketConfig();
|
||||
|
||||
/**
|
||||
* Configuration if using Multicast for clustering communication.
|
||||
*/
|
||||
MulticastConfig multicastConfig = new MulticastConfig();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// MulticastConfig
|
||||
|
||||
/**
|
||||
* The configuration for clustering using Multicast networking.
|
||||
*/
|
||||
public static class MulticastConfig {
|
||||
|
||||
int managerSleepMillis = 80;
|
||||
int lastSendTimeFreqSecs = 300;//5mins
|
||||
int lastStatusTimeFreqSecs = 600;//10mins
|
||||
int maxResendOutgoingAttempts = 200;
|
||||
int maxResendIncomingRequests = 50;
|
||||
|
||||
int listenPort;
|
||||
String listenAddress;
|
||||
int sendPort;
|
||||
String sendAddress;
|
||||
|
||||
// Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507
|
||||
int maxSendPacketSize = 1500;
|
||||
|
||||
// Whether to send packets even when there are no other members online
|
||||
boolean sendWithNoMembers = true;
|
||||
|
||||
// When multiple instances are on same box you need to broadcast back locally
|
||||
boolean disableLoopback;
|
||||
int listenTimeToLive = -1;
|
||||
int listenTimeout = 1000;
|
||||
int listenBufferSize = 65500;
|
||||
// For multihomed environment the address the listener should bind to
|
||||
String listenBindAddress;
|
||||
|
||||
/**
|
||||
* Return the manager sleep millis.
|
||||
*/
|
||||
public int getManagerSleepMillis() {
|
||||
return managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the manager sleep millis.
|
||||
*/
|
||||
public void setManagerSleepMillis(int managerSleepMillis) {
|
||||
this.managerSleepMillis = managerSleepMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last send time frequency.
|
||||
*/
|
||||
public int getLastSendTimeFreqSecs() {
|
||||
return lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last send time frequency.
|
||||
*/
|
||||
public void setLastSendTimeFreqSecs(int lastSendTimeFreqSecs) {
|
||||
this.lastSendTimeFreqSecs = lastSendTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last status time frequency.
|
||||
*/
|
||||
public int getLastStatusTimeFreqSecs() {
|
||||
return lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the last status time frequency.
|
||||
*/
|
||||
public void setLastStatusTimeFreqSecs(int lastStatusTimeFreqSecs) {
|
||||
this.lastStatusTimeFreqSecs = lastStatusTimeFreqSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will try to re-send a given packet before giving up sending
|
||||
*/
|
||||
public int getMaxResendOutgoingAttempts() {
|
||||
return maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for outgoing messages.
|
||||
*/
|
||||
public void setMaxResendOutgoingAttempts(int maxResendOutgoingAttempts) {
|
||||
this.maxResendOutgoingAttempts = maxResendOutgoingAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of times we will ask for a packet to be resent to us before giving up asking.
|
||||
*/
|
||||
public int getMaxResendIncomingRequests() {
|
||||
return maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum retry attempts for incoming messages.
|
||||
*/
|
||||
public void setMaxResendIncomingRequests(int maxResendIncomingRequests) {
|
||||
this.maxResendIncomingRequests = maxResendIncomingRequests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen port.
|
||||
*/
|
||||
public int getListenPort() {
|
||||
return listenPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen port.
|
||||
*/
|
||||
public void setListenPort(int port) {
|
||||
this.listenPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen address.
|
||||
*/
|
||||
public String getListenAddress() {
|
||||
return listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen address.
|
||||
*/
|
||||
public void setListenAddress(String listenAddress) {
|
||||
this.listenAddress = listenAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send port.
|
||||
*/
|
||||
public int getSendPort() {
|
||||
return sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send port.
|
||||
*/
|
||||
public void setSendPort(int sendPort) {
|
||||
this.sendPort = sendPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the send address.
|
||||
*/
|
||||
public String getSendAddress() {
|
||||
return sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the send address.
|
||||
*/
|
||||
public void setSendAddress(String sendAddress) {
|
||||
this.sendAddress = sendAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum send packet size.
|
||||
*/
|
||||
public int getMaxSendPacketSize() {
|
||||
return maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum send packet size. Note 1500 is Ethernet MTU and this must be less than UDP max packet size of 65507.
|
||||
*/
|
||||
public void setMaxSendPacketSize(int maxSendPacketSize) {
|
||||
this.maxSendPacketSize = maxSendPacketSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public boolean isSendWithNoMembers() {
|
||||
return sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set true if send messages when no other members in the cluster are up.
|
||||
*/
|
||||
public void setSendWithNoMembers(boolean sendWithNoMembers) {
|
||||
this.sendWithNoMembers = sendWithNoMembers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public boolean isDisableLoopback() {
|
||||
return disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if loopback is disabled. When multiple instances are on same box you need to broadcast back locally.
|
||||
*/
|
||||
public void setDisableLoopback(boolean disableLoopback) {
|
||||
this.disableLoopback = disableLoopback;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen time to live.
|
||||
*/
|
||||
public int getListenTimeToLive() {
|
||||
return listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen time to live.
|
||||
*/
|
||||
public void setListenTimeToLive(int listenTimeToLive) {
|
||||
this.listenTimeToLive = listenTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen timeout.
|
||||
*/
|
||||
public int getListenTimeout() {
|
||||
return listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the listen timeout.
|
||||
*/
|
||||
public void setListenTimeout(int listenTimeout) {
|
||||
this.listenTimeout = listenTimeout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listen buffer size.
|
||||
*/
|
||||
public int getListenBufferSize() {
|
||||
return listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listen buffer size.
|
||||
*/
|
||||
public void setListenBufferSize(int listenBufferSize) {
|
||||
this.listenBufferSize = listenBufferSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public String getListenBindAddress() {
|
||||
return listenBindAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the listener bind address (optional). For multihomed environment the address the listener should bind to.
|
||||
*/
|
||||
public void setListenBindAddress(String listenBindAddress) {
|
||||
this.listenBindAddress = listenBindAddress;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// SocketConfig
|
||||
|
||||
/**
|
||||
* Configuration for clustering using TCP sockets.
|
||||
* <p>
|
||||
* This is good for when there are relatively small number of cluster members.
|
||||
*/
|
||||
public static class SocketConfig {
|
||||
|
||||
/**
|
||||
* This local server in host:port format.
|
||||
*/
|
||||
String localHostPort;
|
||||
|
||||
/**
|
||||
* All the cluster members in host:port format.
|
||||
*/
|
||||
List<String> members = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* core threads for the associated thread pool.
|
||||
*/
|
||||
int coreThreads = 2;
|
||||
|
||||
/**
|
||||
* Max threads for the associated thread pool.
|
||||
*/
|
||||
int maxThreads = 16;
|
||||
|
||||
String threadPoolName = "EbeanCluster";
|
||||
|
||||
/**
|
||||
* Return the host and port for this server instance.
|
||||
*/
|
||||
public String getLocalHostPort() {
|
||||
return localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the host and port for this server instance.
|
||||
*/
|
||||
public void setLocalHostPort(String localHostPort) {
|
||||
this.localHostPort = localHostPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set all the host and port for all the members of the cluster.
|
||||
*/
|
||||
public void setMembers(List<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of core threads to use.
|
||||
*/
|
||||
public int getCoreThreads() {
|
||||
return coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of core threads to use.
|
||||
*/
|
||||
public void setCoreThreads(int coreThreads) {
|
||||
this.coreThreads = coreThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of max threads to use.
|
||||
*/
|
||||
public int getMaxThreads() {
|
||||
return maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the number of max threads to use.
|
||||
*/
|
||||
public void setMaxThreads(int maxThreads) {
|
||||
this.maxThreads = maxThreads;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the thread pool name.
|
||||
*/
|
||||
public String getThreadPoolName() {
|
||||
return threadPoolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the thread pool name.
|
||||
*/
|
||||
public void setThreadPoolName(String threadPoolName) {
|
||||
this.threadPoolName = threadPoolName;
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
// Members
|
||||
|
||||
/**
|
||||
* Load the settings from properties.
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
//TODO
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster mode.
|
||||
*/
|
||||
public ClusterMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster mode.
|
||||
*/
|
||||
public void setMode(ClusterMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the socket communication configuration.
|
||||
*/
|
||||
public SocketConfig getSocketConfig() {
|
||||
return socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the socket communication configuration.
|
||||
*/
|
||||
public void setSocketConfig(SocketConfig socketConfig) {
|
||||
this.socketConfig = socketConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the multicast communication configuration.
|
||||
*/
|
||||
public MulticastConfig getMulticastConfig() {
|
||||
return multicastConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the multicast communication configuration.
|
||||
*/
|
||||
public void setMulticastConfig(MulticastConfig multicastConfig) {
|
||||
this.multicastConfig = multicastConfig;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.avaje.ebean.config;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import com.avaje.ebean.Transaction;
|
||||
import com.avaje.ebean.util.StringHelper;
|
||||
@@ -448,48 +449,63 @@ public class DataSourceConfig {
|
||||
this.customProperties = customProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings by reading the ebean.properties file.
|
||||
*
|
||||
* @param serverName name of the server
|
||||
*/
|
||||
public void loadSettings(String serverName) {
|
||||
loadSettingsCustomPrefix("datasource." + serverName + ".", new GlobalProperties.DelegatedGlobalPropertySource(serverName));
|
||||
loadSettings(new PropertiesWrapper("datasource", serverName, PropertyMap.defaultProperties()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from ebean.properties.
|
||||
* Load the settings from the properties supplied.
|
||||
* <p>
|
||||
* You can use this when you have your own properties to use for configuration.
|
||||
* </p>
|
||||
*
|
||||
* @param properties the properties to configure the datasource
|
||||
* @param serverName the name of the specific datasource (optional)
|
||||
*/
|
||||
public void loadSettingsCustomPrefix(String prefix, GlobalProperties.PropertySource properties) {
|
||||
public void loadSettings(Properties properties, String serverName) {
|
||||
PropertiesWrapper dbProps = new PropertiesWrapper("datasource", serverName, properties);
|
||||
loadSettings(dbProps);
|
||||
}
|
||||
|
||||
this.username = properties.get(prefix + "username", null);
|
||||
this.password = properties.get(prefix + "password", null);
|
||||
/**
|
||||
* Load the settings from the PropertiesWrapper.
|
||||
*/
|
||||
public void loadSettings(PropertiesWrapper properties) {
|
||||
|
||||
String dbDriver = properties.get(prefix + "databaseDriver", null);
|
||||
this.driver = properties.get(prefix + "driver", dbDriver);
|
||||
username = properties.get("username", username);
|
||||
password = properties.get("password", password);
|
||||
driver = properties.get("driver", properties.get("databaseDriver", driver));
|
||||
url = properties.get("url", properties.get("databaseUrl", url));
|
||||
|
||||
String dbUrl = properties.get(prefix + "databaseUrl", null);
|
||||
this.url = properties.get(prefix + "url", dbUrl);
|
||||
autoCommit = properties.getBoolean("autoCommit", autoCommit);
|
||||
captureStackTrace = properties.getBoolean("captureStackTrace", captureStackTrace);
|
||||
maxStackTraceSize = properties.getInt("maxStackTraceSize", maxStackTraceSize);
|
||||
leakTimeMinutes = properties.getInt("leakTimeMinutes", leakTimeMinutes);
|
||||
maxInactiveTimeSecs = properties.getInt("maxInactiveTimeSecs", maxInactiveTimeSecs);
|
||||
trimPoolFreqSecs = properties.getInt("trimPoolFreqSecs", trimPoolFreqSecs);
|
||||
maxAgeMinutes = properties.getInt("maxAgeMinutes", maxAgeMinutes);
|
||||
|
||||
this.autoCommit = properties.getBoolean(prefix + "autoCommit", false);
|
||||
this.captureStackTrace = properties.getBoolean(prefix + "captureStackTrace", false);
|
||||
this.maxStackTraceSize = properties.getInt(prefix + "maxStackTraceSize", 5);
|
||||
this.leakTimeMinutes = properties.getInt(prefix + "leakTimeMinutes", 30);
|
||||
this.maxInactiveTimeSecs = properties.getInt(prefix + "maxInactiveTimeSecs", 720);
|
||||
this.trimPoolFreqSecs = properties.getInt(prefix + "trimPoolFreqSecs", 59);
|
||||
this.maxAgeMinutes = properties.getInt(prefix + "maxAgeMinutes", 0);
|
||||
minConnections = properties.getInt("minConnections", minConnections);
|
||||
maxConnections = properties.getInt("maxConnections", maxConnections);
|
||||
pstmtCacheSize = properties.getInt("pstmtCacheSize", pstmtCacheSize);
|
||||
cstmtCacheSize = properties.getInt("cstmtCacheSize", cstmtCacheSize);
|
||||
|
||||
this.minConnections = properties.getInt(prefix + "minConnections", 0);
|
||||
this.maxConnections = properties.getInt(prefix + "maxConnections", 20);
|
||||
this.pstmtCacheSize = properties.getInt(prefix + "pstmtCacheSize", 20);
|
||||
this.cstmtCacheSize = properties.getInt(prefix + "cstmtCacheSize", 20);
|
||||
waitTimeoutMillis = properties.getInt("waitTimeout", waitTimeoutMillis);
|
||||
|
||||
this.waitTimeoutMillis = properties.getInt(prefix + "waitTimeout", 1000);
|
||||
heartbeatSql = properties.get("heartbeatSql", heartbeatSql);
|
||||
heartbeatTimeoutSeconds = properties.getInt("heartbeatTimeoutSeconds", heartbeatTimeoutSeconds);
|
||||
poolListener = properties.get("poolListener", poolListener);
|
||||
offline = properties.getBoolean("offline", offline);
|
||||
|
||||
this.heartbeatSql = properties.get(prefix + "heartbeatSql", null);
|
||||
this.heartbeatTimeoutSeconds = properties.getInt(prefix + "heartbeatTimeoutSeconds", 3);
|
||||
this.poolListener = properties.get(prefix + "poolListener", null);
|
||||
this.offline = properties.getBoolean(prefix + "offline", false);
|
||||
|
||||
String isoLevel = properties.get(prefix + "isolationlevel", "READ_COMMITTED");
|
||||
String isoLevel = properties.get("isolationlevel", getTransactionIsolationLevel(isolationLevel));
|
||||
this.isolationLevel = getTransactionIsolationLevel(isoLevel);
|
||||
|
||||
String customProperties = properties.get(prefix + "customProperties", null);
|
||||
String customProperties = properties.get("customProperties", null);
|
||||
if (customProperties != null && customProperties.length() > 0) {
|
||||
Map<String, String> custProps = StringHelper.delimitedToMap(customProperties, ";", "=");
|
||||
this.customProperties = custProps;
|
||||
@@ -498,7 +514,21 @@ public class DataSourceConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* return the isolation level for a given string description.
|
||||
* Return the isolation level description from the associated Connection int value.
|
||||
*/
|
||||
public String getTransactionIsolationLevel(int level) {
|
||||
switch (level) {
|
||||
case Connection.TRANSACTION_NONE : return "NONE";
|
||||
case Connection.TRANSACTION_READ_COMMITTED : return "READ_COMMITTED";
|
||||
case Connection.TRANSACTION_READ_UNCOMMITTED : return "READ_UNCOMMITTED";
|
||||
case Connection.TRANSACTION_REPEATABLE_READ : return "REPEATABLE_READ";
|
||||
case Connection.TRANSACTION_SERIALIZABLE : return "SERIALIZABLE";
|
||||
default: throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the isolation level for a given string description.
|
||||
*/
|
||||
public int getTransactionIsolationLevel(String level) {
|
||||
level = level.toUpperCase();
|
||||
@@ -522,6 +552,6 @@ public class DataSourceConfig {
|
||||
return Connection.TRANSACTION_SERIALIZABLE;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Transaction Isolaction level [" + level + "] is not known.");
|
||||
throw new RuntimeException("Transaction Isolation level [" + level + "] is not known.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.avaje.ebean.util.ClassUtil;
|
||||
|
||||
/**
|
||||
* Provides access to properties loaded from the ebean.properties file.
|
||||
*/
|
||||
public final class GlobalProperties {
|
||||
|
||||
private static volatile PropertyMap globalMap;
|
||||
|
||||
private static boolean skipPrimaryServer;
|
||||
|
||||
/**
|
||||
* Set whether to skip automatically creating the primary server.
|
||||
*/
|
||||
public static synchronized void setSkipPrimaryServer(boolean skip) {
|
||||
skipPrimaryServer = skip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true to skip automatically creating the primary server.
|
||||
*/
|
||||
public static synchronized boolean isSkipPrimaryServer() {
|
||||
return skipPrimaryServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the string replacing any expressions like ${catalina.base}.
|
||||
* <p>
|
||||
* This will evaluate expressions using first environment variables, than java
|
||||
* system variables and lastly properties in ebean.properties - in that order.
|
||||
* </p>
|
||||
* <p>
|
||||
* Expressions start with "${" and end with "}".
|
||||
* </p>
|
||||
*/
|
||||
public static String evaluateExpressions(String val) {
|
||||
return getPropertyMap().eval(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and evaluate any expressions that have not already been evaluated.
|
||||
*/
|
||||
public static synchronized void evaluateExpressions() {
|
||||
getPropertyMap().evaluateProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* In a servlet container environment this will additionally look in WEB-INF
|
||||
* for the ebean.properties file.
|
||||
*/
|
||||
public static synchronized void setServletContext(ServletContext servletContext) {
|
||||
|
||||
PropertyMapLoader.setServletContext(servletContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ServletContext (if setup in a servlet container environment).
|
||||
*/
|
||||
public static synchronized ServletContext getServletContext() {
|
||||
|
||||
return PropertyMapLoader.getServletContext();
|
||||
}
|
||||
|
||||
private static void initPropertyMap() {
|
||||
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
globalMap = PropertyMapLoader.load(null, fileName);
|
||||
if (globalMap == null) {
|
||||
// ebean.properties file was not found... but that
|
||||
// is ok because we are likely doing programmatic config
|
||||
globalMap = new PropertyMap();
|
||||
}
|
||||
|
||||
String loaderCn = globalMap.get("ebean.properties.loader");
|
||||
if (loaderCn != null) {
|
||||
// a Runnable that can be used to customise the initialisation
|
||||
// of the GlobalProperties
|
||||
try {
|
||||
Runnable r = (Runnable) ClassUtil.newInstance(loaderCn);
|
||||
r.run();
|
||||
} catch (Exception e) {
|
||||
String m = "Error creating or running properties loader " + loaderCn;
|
||||
throw new RuntimeException(m, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property map loading it if required.
|
||||
*/
|
||||
private static synchronized PropertyMap getPropertyMap() {
|
||||
|
||||
if (globalMap == null) {
|
||||
initPropertyMap();
|
||||
}
|
||||
|
||||
return globalMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String property with a default value.
|
||||
*/
|
||||
public static synchronized String get(String key, String defaultValue) {
|
||||
return getPropertyMap().get(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a int property with a default value.
|
||||
*/
|
||||
public static synchronized int getInt(String key, int defaultValue) {
|
||||
return getPropertyMap().getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean property with a default value.
|
||||
*/
|
||||
public static synchronized boolean getBoolean(String key, boolean defaultValue) {
|
||||
return getPropertyMap().getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a property return the previous value. This will evaluate any
|
||||
* expressions in the value.
|
||||
*/
|
||||
public static synchronized String put(String key, String value) {
|
||||
return getPropertyMap().putEval(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a Map of key value properties.
|
||||
*/
|
||||
public static synchronized void putAll(Map<String, String> keyValueMap) {
|
||||
for (Entry<String, String> e : keyValueMap.entrySet()) {
|
||||
getPropertyMap().putEval(e.getKey(), e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
public static PropertySource getPropertySource(String name) {
|
||||
return new ConfigPropertyMap(name);
|
||||
}
|
||||
|
||||
public static interface PropertySource {
|
||||
|
||||
/**
|
||||
* Return the name of the server. This is also the dataSource name.
|
||||
*/
|
||||
public String getServerName();
|
||||
|
||||
/**
|
||||
* Get a property. This will prepend "ebean" and the server name to lookup
|
||||
* the value.
|
||||
*/
|
||||
public String get(String key, String defaultValue);
|
||||
|
||||
public int getInt(String key, int defaultValue);
|
||||
|
||||
public boolean getBoolean(String key, boolean defaultValue);
|
||||
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue);
|
||||
|
||||
}
|
||||
|
||||
public static class DelegatedGlobalPropertySource implements PropertySource {
|
||||
|
||||
private String serverName;
|
||||
|
||||
public DelegatedGlobalPropertySource(String serverName) {
|
||||
this.serverName = serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key, String defaultValue) {
|
||||
return GlobalProperties.get(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String key, int defaultValue) {
|
||||
return GlobalProperties.getInt(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return GlobalProperties.getBoolean(key, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,4 +112,9 @@ public interface NamingConvention {
|
||||
*/
|
||||
public boolean isUseForeignKeyPrefix();
|
||||
|
||||
/**
|
||||
* Load setting from properties.
|
||||
*/
|
||||
public void loadFromProperties(PropertiesWrapper properties);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
public class PropertiesWrapper {
|
||||
|
||||
protected final Properties properties;
|
||||
|
||||
protected final String prefix;
|
||||
|
||||
protected final String serverName;
|
||||
|
||||
protected final PropertyMap propertyMap;
|
||||
|
||||
/**
|
||||
* Construct with a prefix, serverName and properties.
|
||||
*/
|
||||
public PropertiesWrapper(String prefix, String serverName, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = PropertyMapLoader.load(null, properties);
|
||||
this.properties = propertyMap.asProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct without prefix of serverName.
|
||||
*/
|
||||
public PropertiesWrapper(Properties properties) {
|
||||
this(null, null, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal copy constructor when changing prefix.
|
||||
*/
|
||||
protected PropertiesWrapper(String prefix, String serverName, PropertyMap propertyMap, Properties properties) {
|
||||
this.serverName = serverName;
|
||||
this.prefix = prefix;
|
||||
this.propertyMap = propertyMap;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PropertiesWrapper instance with a different prefix but same underlying properties.
|
||||
* <p/>
|
||||
* Used when wanting to use "datasource" as the prefix rather than "ebean".
|
||||
* <p/>
|
||||
* The returning instance should only be used in a read only fashion.
|
||||
*/
|
||||
public PropertiesWrapper withPrefix(String prefix) {
|
||||
return new PropertiesWrapper(prefix, serverName, propertyMap, properties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the serverName (optional).
|
||||
*/
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as Properties with lower case keys and after evaluation and additional properties loading has occurred.
|
||||
* <p>
|
||||
* Ebean has historically ignored the case of keys hence returning the Properties with all the keys lower cased.
|
||||
* </p>
|
||||
*/
|
||||
public Properties asPropertiesLowerCase() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with no default value.
|
||||
*/
|
||||
public String get(String key) {
|
||||
return get(key, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a property with a default value.
|
||||
* <p>
|
||||
* This performs a search using the prefix and server name (if supplied) to search for the property
|
||||
* value in order based on:
|
||||
* <pre>{@code
|
||||
* prefix.serverName.key
|
||||
* prefix.key
|
||||
* key
|
||||
* }</pre>
|
||||
* </p>
|
||||
*/
|
||||
public String get(String key, String defaultValue) {
|
||||
|
||||
String value = null;
|
||||
if (serverName != null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + serverName + "." + key, null);
|
||||
}
|
||||
if (value == null && prefix != null) {
|
||||
value = propertyMap.get(prefix + "." + key, null);
|
||||
}
|
||||
if (value == null) {
|
||||
value = propertyMap.get(key, null);
|
||||
}
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a double property value.
|
||||
*/
|
||||
public double getDouble(String key, double defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Double.parseDouble(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an int property value.
|
||||
*/
|
||||
public int getInt(String key, int defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a long property value.
|
||||
*/
|
||||
public long getLong(String key, long defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a boolean property value.
|
||||
*/
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
|
||||
String value = get(key, String.valueOf(defaultValue));
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Enum property value.
|
||||
*/
|
||||
public <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T defaultValue) {
|
||||
String level = get(key, defaultValue.name());
|
||||
return Enum.valueOf(enumType, level.toUpperCase());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,21 +4,40 @@ import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A map like structure of properties.
|
||||
* <p/>
|
||||
* Handles evaluation of expressions like ${home} and provides convenience methods for int, long and boolean.
|
||||
*/
|
||||
final class PropertyMap implements Serializable {
|
||||
public final class PropertyMap implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
|
||||
|
||||
public static Properties defaultProperties() {
|
||||
PropertyMap propertyMap = PropertyMapLoader.loadGlobalProperties();
|
||||
return (propertyMap == null) ? new Properties() : propertyMap.asProperties();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return map.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return as standard Properties.
|
||||
*/
|
||||
public Properties asProperties() {
|
||||
Properties properties = new Properties();
|
||||
for (Entry<String, String> e : entrySet()) {
|
||||
properties.put(e.getKey(), e.getValue());
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Go through all the properties and evaluate any expressions that have not
|
||||
* been resolved.
|
||||
@@ -35,10 +54,16 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value with expressions like ${home} evaluated using system properties and environment variables.
|
||||
*/
|
||||
public synchronized String eval(String val) {
|
||||
return PropertyExpression.eval(val, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the boolean property value with a given default.
|
||||
*/
|
||||
public synchronized boolean getBoolean(String key, boolean defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
@@ -48,6 +73,9 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the int property value with a given default.
|
||||
*/
|
||||
public synchronized int getInt(String key, int defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
@@ -57,36 +85,69 @@ final class PropertyMap implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the long property value with a given default.
|
||||
*/
|
||||
public synchronized long getLong(String key, long defaultValue) {
|
||||
String value = get(key);
|
||||
if (value == null) {
|
||||
return defaultValue;
|
||||
} else {
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the string property value with a given default.
|
||||
*/
|
||||
public synchronized String get(String key, String defaultValue) {
|
||||
String value = map.get(key.toLowerCase());
|
||||
return value == null ? defaultValue : value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the property value returning null if there is no value defined.
|
||||
*/
|
||||
public synchronized String get(String key) {
|
||||
return map.get(key.toLowerCase());
|
||||
}
|
||||
|
||||
synchronized void putAll(Map<String, String> keyValueMap) {
|
||||
/**
|
||||
* Put all evaluating any expressions in the values.
|
||||
*/
|
||||
public synchronized void putEvalAll(Map<String, String> keyValueMap) {
|
||||
|
||||
for (Map.Entry<String, String> entry : keyValueMap.entrySet()) {
|
||||
put(entry.getKey(), entry.getValue());
|
||||
putEval(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
synchronized String putEval(String key, String value) {
|
||||
/**
|
||||
* Put a single key value evaluating any expressions in the value.
|
||||
*/
|
||||
public synchronized String putEval(String key, String value) {
|
||||
value = PropertyExpression.eval(value, this);
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
synchronized String put(String key, String value) {
|
||||
/**
|
||||
* Put a single key value with no expression evaluation.
|
||||
*/
|
||||
public synchronized String put(String key, String value) {
|
||||
return map.put(key.toLowerCase(), value);
|
||||
}
|
||||
|
||||
synchronized String remove(String key) {
|
||||
/**
|
||||
* Remove an entry.
|
||||
*/
|
||||
public synchronized String remove(String key) {
|
||||
return map.remove(key.toLowerCase());
|
||||
}
|
||||
|
||||
synchronized Set<Entry<String, String>> entrySet() {
|
||||
/**
|
||||
* Return the entries.
|
||||
*/
|
||||
public synchronized Set<Entry<String, String>> entrySet() {
|
||||
return map.entrySet();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,40 +1,30 @@
|
||||
package com.avaje.ebean.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Helper used to load the PropertyMap.
|
||||
* Helper used to load the ebean.properties into a PropertyMap.
|
||||
*/
|
||||
final class PropertyMapLoader {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PropertyMapLoader.class);
|
||||
|
||||
private static ServletContext servletContext;
|
||||
public static PropertyMap loadGlobalProperties() {
|
||||
|
||||
/**
|
||||
* Return the servlet context when in a web environment.
|
||||
*/
|
||||
public static ServletContext getServletContext() {
|
||||
return servletContext;
|
||||
}
|
||||
String fileName = System.getenv("EBEAN_PROPS_FILE");
|
||||
if (fileName == null) {
|
||||
fileName = System.getProperty("ebean.props.file");
|
||||
if (fileName == null) {
|
||||
fileName = "ebean.properties";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the ServletContext for when ebean.properties is in WEB-INF in a web
|
||||
* application environment.
|
||||
*/
|
||||
public static void setServletContext(ServletContext servletContext) {
|
||||
PropertyMapLoader.servletContext = servletContext;
|
||||
return load(null, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,15 +54,20 @@ final class PropertyMapLoader {
|
||||
* @param in
|
||||
* the InputStream of the properties file to load.
|
||||
*/
|
||||
private static PropertyMap load(PropertyMap p, InputStream in) {
|
||||
public static PropertyMap load(PropertyMap p, InputStream in) {
|
||||
|
||||
Properties props = new Properties();
|
||||
try {
|
||||
props.load(in);
|
||||
in.close();
|
||||
return load(p, props);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static PropertyMap load(PropertyMap p, Properties props) {
|
||||
|
||||
if (p == null) {
|
||||
p = new PropertyMap();
|
||||
@@ -117,18 +112,6 @@ final class PropertyMapLoader {
|
||||
throw new NullPointerException("fileName is null?");
|
||||
}
|
||||
|
||||
if (servletContext == null) {
|
||||
logger.debug("No servletContext so not looking in WEB-INF for " + fileName);
|
||||
|
||||
} else {
|
||||
// first look in WEB-INF ...
|
||||
InputStream in = servletContext.getResourceAsStream("/WEB-INF/" + fileName);
|
||||
if (in != null) {
|
||||
logger.debug(fileName + " found in WEB-INF");
|
||||
return in;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File f = new File(fileName);
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ 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.config.GlobalProperties.PropertySource;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.event.*;
|
||||
@@ -16,6 +15,7 @@ import com.fasterxml.jackson.core.JsonFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* The configuration used for creating a EbeanServer.
|
||||
@@ -30,9 +30,9 @@ import java.util.List;
|
||||
* classes and listeners etc.
|
||||
* </p>
|
||||
*
|
||||
* <pre class="code">
|
||||
* <pre>{@code
|
||||
* ServerConfig c = new ServerConfig();
|
||||
* c.setName("ordh2");
|
||||
* c.setName("ordh2");
|
||||
*
|
||||
* // read the ebean.properties and load
|
||||
* // those settings into this serverConfig object
|
||||
@@ -43,18 +43,18 @@ import java.util.List;
|
||||
* c.setDdlRun(true);
|
||||
*
|
||||
* // add any classes found in the app.data package
|
||||
* c.addPackage("app.data");
|
||||
* c.addPackage("app.data");
|
||||
*
|
||||
* // add the names of Jars that contain entities
|
||||
* c.addJar("myJarContainingEntities.jar");
|
||||
* c.addJar("someOtherJarContainingEntities.jar");
|
||||
* c.addJar("myJarContainingEntities.jar");
|
||||
* c.addJar("someOtherJarContainingEntities.jar");
|
||||
*
|
||||
* // register as the 'Default' server
|
||||
* c.setDefaultServer(true);
|
||||
*
|
||||
* EbeanServer server = EbeanServerFactory.create(c);
|
||||
*
|
||||
* </pre>
|
||||
* }</pre>
|
||||
*
|
||||
* @see EbeanServerFactory
|
||||
*
|
||||
@@ -62,17 +62,14 @@ import java.util.List;
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class ServerConfig {
|
||||
|
||||
/**
|
||||
* The Constant DEFAULT_QUERY_BATCH_SIZE. Default: 100
|
||||
*/
|
||||
private final static int DEFAULT_QUERY_BATCH_SIZE = 100;
|
||||
|
||||
/**
|
||||
* The EbeanServer name.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
private ContainerConfig containerConfig;
|
||||
|
||||
/**
|
||||
* The resource directory.
|
||||
*/
|
||||
@@ -111,6 +108,11 @@ public class ServerConfig {
|
||||
*/
|
||||
private List<String> searchJars = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Class name of a classPathReader implementation.
|
||||
*/
|
||||
private String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Config controlling the autofetch behaviour.
|
||||
*/
|
||||
@@ -146,9 +148,11 @@ public class ServerConfig {
|
||||
private int lazyLoadBatchSize = 1;
|
||||
|
||||
/**
|
||||
* The query batch size.
|
||||
* The default batch size for 'query joins'.
|
||||
*/
|
||||
private int queryBatchSize = -1;
|
||||
private int queryBatchSize = 100;
|
||||
|
||||
private boolean eagerFetchLobs;
|
||||
|
||||
private boolean ddlGenerate;
|
||||
|
||||
@@ -201,7 +205,7 @@ public class ServerConfig {
|
||||
/**
|
||||
* The naming convention.
|
||||
*/
|
||||
private NamingConvention namingConvention;
|
||||
private NamingConvention namingConvention = new UnderscoreNamingConvention();
|
||||
|
||||
/**
|
||||
* Behaviour of update to include on the change properties.
|
||||
@@ -238,9 +242,9 @@ public class ServerConfig {
|
||||
|
||||
private ServerCacheManager serverCacheManager;
|
||||
|
||||
private boolean collectQueryStatsByNode;
|
||||
private boolean collectQueryStatsByNode = true;
|
||||
|
||||
private boolean collectQueryOrigins;
|
||||
private boolean collectQueryOrigins = true;
|
||||
|
||||
/**
|
||||
* The default PersistenceContextScope used if one is not explicitly set on a query.
|
||||
@@ -253,6 +257,33 @@ public class ServerConfig {
|
||||
|
||||
private boolean durationWithNanos;
|
||||
|
||||
private int maxCallStack = 5;
|
||||
|
||||
private boolean transactionRollbackOnChecked = true;
|
||||
|
||||
private boolean registerJmxMBeans = true;
|
||||
|
||||
// configuration for the background executor service (thread pool)
|
||||
|
||||
private int backgroundExecutorSchedulePoolSize = 1;
|
||||
private int backgroundExecutorCorePoolSize = 1;
|
||||
private int backgroundExecutorMaxPoolSize = 8;
|
||||
private int backgroundExecutorIdleSecs = 60;
|
||||
private int backgroundExecutorShutdownSecs = 30;
|
||||
|
||||
// defaults for the L2 bean caching
|
||||
|
||||
private int cacheWarmingDelay = 30;
|
||||
private int cacheMaxSize = 10000;
|
||||
private int cacheMaxIdleTime = 600;
|
||||
private int cacheMaxTimeToLive = 60*60*6;
|
||||
|
||||
// defaults for the L2 query caching
|
||||
|
||||
private int queryCacheMaxSize = 1000;
|
||||
private int queryCacheMaxIdleTime = 600;
|
||||
private int queryCacheMaxTimeToLive = 60*60*6;
|
||||
|
||||
/**
|
||||
* Construct a Server Configuration for programmatically creating an EbeanServer.
|
||||
*/
|
||||
@@ -306,6 +337,26 @@ public class ServerConfig {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
*/
|
||||
public ContainerConfig getContainerConfig() {
|
||||
return containerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the container / clustering configuration.
|
||||
* <p/>
|
||||
* The container holds all the EbeanServer instances and provides clustering communication
|
||||
* services to all the EbeanServer instances.
|
||||
*/
|
||||
public void setContainerConfig(ContainerConfig containerConfig) {
|
||||
this.containerConfig = containerConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this server should be registered with the Ebean singleton
|
||||
* when it is created.
|
||||
@@ -362,15 +413,6 @@ public class ServerConfig {
|
||||
return persistBatching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use isPersistBatching() instead.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public boolean isUsePersistBatching() {
|
||||
return persistBatching;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if you what to use JDBC batching for persisting and deleting
|
||||
* beans.
|
||||
@@ -532,6 +574,234 @@ public class ServerConfig {
|
||||
this.enhanceLogLevel = enhanceLogLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if LOB's should default to fetch eager.
|
||||
* By default this is set to false and LOB's must be explicitly fetched.
|
||||
*/
|
||||
public boolean isEagerFetchLobs() {
|
||||
return eagerFetchLobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if you want LOB's to be fetch eager by default.
|
||||
* By default this is set to false and LOB's must be explicitly fetched.
|
||||
*/
|
||||
public void setEagerFetchLobs(boolean eagerFetchLobs) {
|
||||
this.eagerFetchLobs = eagerFetchLobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the max call stack to use for origin location.
|
||||
*/
|
||||
public int getMaxCallStack() {
|
||||
return maxCallStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max call stack to use for origin location.
|
||||
*/
|
||||
public void setMaxCallStack(int maxCallStack) {
|
||||
this.maxCallStack = maxCallStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if transactions should rollback on checked exceptions.
|
||||
*/
|
||||
public boolean isTransactionRollbackOnChecked() {
|
||||
return transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if transactions should by default rollback on checked exceptions.
|
||||
*/
|
||||
public void setTransactionRollbackOnChecked(boolean transactionRollbackOnChecked) {
|
||||
this.transactionRollbackOnChecked = transactionRollbackOnChecked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the server should register JMX MBeans.
|
||||
*/
|
||||
public boolean isRegisterJmxMBeans() {
|
||||
return registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if the server should register JMX MBeans.
|
||||
*/
|
||||
public void setRegisterJmxMBeans(boolean registerJmxMBeans) {
|
||||
this.registerJmxMBeans = registerJmxMBeans;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor schedule pool size. Defaults to 1.
|
||||
*/
|
||||
public int getBackgroundExecutorSchedulePoolSize() {
|
||||
return backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor schedule pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorSchedulePoolSize(int backgroundExecutorSchedulePoolSize) {
|
||||
this.backgroundExecutorSchedulePoolSize = backgroundExecutorSchedulePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor core pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorCorePoolSize() {
|
||||
return backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor core pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorCorePoolSize(int backgroundExecutorCorePoolSize) {
|
||||
this.backgroundExecutorCorePoolSize = backgroundExecutorCorePoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor max pool size.
|
||||
*/
|
||||
public int getBackgroundExecutorMaxPoolSize() {
|
||||
return backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor max pool size.
|
||||
*/
|
||||
public void setBackgroundExecutorMaxPoolSize(int backgroundExecutorMaxPoolSize) {
|
||||
this.backgroundExecutorMaxPoolSize = backgroundExecutorMaxPoolSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor idle seconds.
|
||||
*/
|
||||
public int getBackgroundExecutorIdleSecs() {
|
||||
return backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor idle seconds.
|
||||
*/
|
||||
public void setBackgroundExecutorIdleSecs(int backgroundExecutorIdleSecs) {
|
||||
this.backgroundExecutorIdleSecs = backgroundExecutorIdleSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
*/
|
||||
public int getBackgroundExecutorShutdownSecs() {
|
||||
return backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Background executor shutdown seconds. This is the time allowed for the pool to shutdown nicely
|
||||
* before it is forced shutdown.
|
||||
*/
|
||||
public void setBackgroundExecutorShutdownSecs(int backgroundExecutorShutdownSecs) {
|
||||
this.backgroundExecutorShutdownSecs = backgroundExecutorShutdownSecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cache warming delay in seconds.
|
||||
*/
|
||||
public int getCacheWarmingDelay() {
|
||||
return cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cache warming delay in seconds.
|
||||
*/
|
||||
public void setCacheWarmingDelay(int cacheWarmingDelay) {
|
||||
this.cacheWarmingDelay = cacheWarmingDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max size.
|
||||
*/
|
||||
public int getCacheMaxSize() {
|
||||
return cacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max size.
|
||||
*/
|
||||
public void setCacheMaxSize(int cacheMaxSize) {
|
||||
this.cacheMaxSize = cacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max idle time in seconds.
|
||||
*/
|
||||
public int getCacheMaxIdleTime() {
|
||||
return cacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max idle time in seconds.
|
||||
*/
|
||||
public void setCacheMaxIdleTime(int cacheMaxIdleTime) {
|
||||
this.cacheMaxIdleTime = cacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 cache default max time to live in seconds.
|
||||
*/
|
||||
public int getCacheMaxTimeToLive() {
|
||||
return cacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 cache default max time to live in seconds.
|
||||
*/
|
||||
public void setCacheMaxTimeToLive(int cacheMaxTimeToLive) {
|
||||
this.cacheMaxTimeToLive = cacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max size.
|
||||
*/
|
||||
public int getQueryCacheMaxSize() {
|
||||
return queryCacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max size.
|
||||
*/
|
||||
public void setQueryCacheMaxSize(int queryCacheMaxSize) {
|
||||
this.queryCacheMaxSize = queryCacheMaxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max idle time in seconds.
|
||||
*/
|
||||
public int getQueryCacheMaxIdleTime() {
|
||||
return queryCacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max idle time in seconds.
|
||||
*/
|
||||
public void setQueryCacheMaxIdleTime(int queryCacheMaxIdleTime) {
|
||||
this.queryCacheMaxIdleTime = queryCacheMaxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the L2 query cache default max time to live in seconds.
|
||||
*/
|
||||
public int getQueryCacheMaxTimeToLive() {
|
||||
return queryCacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the L2 query cache default max time to live in seconds.
|
||||
*/
|
||||
public void setQueryCacheMaxTimeToLive(int queryCacheMaxTimeToLive) {
|
||||
this.queryCacheMaxTimeToLive = queryCacheMaxTimeToLive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the NamingConvention.
|
||||
* <p>
|
||||
@@ -1049,6 +1319,23 @@ public class ServerConfig {
|
||||
this.searchJars = searchJars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the class name of a classPathReader implementation.
|
||||
*/
|
||||
public String getClassPathReaderClassName() {
|
||||
return classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the class name of a classPathReader implementation.
|
||||
*
|
||||
* Refer to server.util.ClassPathReader, this should really by a plugin but doing this for now
|
||||
* to be relatively compatible with current implementation.
|
||||
*/
|
||||
public void setClassPathReaderClassName(String classPathReaderClassName) {
|
||||
this.classPathReaderClassName = classPathReaderClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the list of classes (entities, listeners, scalarTypes etc) that should
|
||||
* be used for this server.
|
||||
@@ -1334,44 +1621,26 @@ public class ServerConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the ebean.properties file.
|
||||
* Load settings from ebean.properties.
|
||||
*/
|
||||
public void loadFromProperties() {
|
||||
ConfigPropertyMap p = new ConfigPropertyMap(name);
|
||||
loadFromProperties(PropertyMap.defaultProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the settings from the given properties
|
||||
*/
|
||||
public void loadFromProperties(Properties properties) {
|
||||
PropertiesWrapper p = new PropertiesWrapper("ebean", name, properties);
|
||||
loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a PropertySource for this server.
|
||||
*/
|
||||
public PropertySource getPropertySource() {
|
||||
return GlobalProperties.getPropertySource(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a configuration property using a default value.
|
||||
*/
|
||||
public String getProperty(String propertyName, String defaultValue) {
|
||||
PropertySource p = new ConfigPropertyMap(name);
|
||||
return p.get(propertyName, defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a configuration property.
|
||||
*/
|
||||
public String getProperty(String propertyName) {
|
||||
return getProperty(propertyName, null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T createInstance(PropertySource p, Class<T> type, String key) {
|
||||
private <T> T createInstance(PropertiesWrapper p, Class<T> pluginType, String key) {
|
||||
|
||||
String classname = p.get(key, null);
|
||||
if (classname == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (T) ClassUtil.newInstance(classname);
|
||||
return classname == null ? null : (T) ClassUtil.newInstance(classname);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1381,36 +1650,37 @@ public class ServerConfig {
|
||||
*
|
||||
* @param p - The defined property source passed to load settings
|
||||
*/
|
||||
protected void loadDataSourceSettings(PropertySource p) {
|
||||
dataSourceConfig.loadSettings(p.getServerName());
|
||||
protected void loadDataSourceSettings(PropertiesWrapper p) {
|
||||
dataSourceConfig.loadSettings(p.withPrefix("datasource"));
|
||||
}
|
||||
|
||||
/**
|
||||
* This is broken out for the same reason as above - preserve existing behaviour but let it be overridden.
|
||||
*/
|
||||
protected void loadAutofetchConfig(PropertySource p) {
|
||||
protected void loadAutofetchSettings(PropertiesWrapper p) {
|
||||
autofetchConfig.loadSettings(p);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the configuration settings from the properties file.
|
||||
*/
|
||||
protected void loadSettings(PropertySource p) {
|
||||
protected void loadSettings(PropertiesWrapper p) {
|
||||
|
||||
if (namingConvention != null) {
|
||||
namingConvention.loadFromProperties(p);
|
||||
}
|
||||
if (autofetchConfig == null) {
|
||||
autofetchConfig = new AutofetchConfig();
|
||||
}
|
||||
|
||||
loadAutofetchConfig(p);
|
||||
loadAutofetchSettings(p);
|
||||
|
||||
if (dataSourceConfig == null) {
|
||||
dataSourceConfig = new DataSourceConfig();
|
||||
}
|
||||
|
||||
loadDataSourceSettings(p);
|
||||
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", false);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", false);
|
||||
autoCommitMode = p.getBoolean("autoCommitMode", autoCommitMode);
|
||||
useJtaTransactionManager = p.getBoolean("useJtaTransactionManager", useJtaTransactionManager);
|
||||
namingConvention = createNamingConvention(p);
|
||||
databasePlatform = createInstance(p, DatabasePlatform.class, "databasePlatform");
|
||||
encryptKeyManager = createInstance(p, EncryptKeyManager.class, "encryptKeyManager");
|
||||
@@ -1425,37 +1695,37 @@ public class ServerConfig {
|
||||
searchJars = getSearchJarsPackages(jarsProp);
|
||||
}
|
||||
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
if (packages != null) {
|
||||
String packagesProp = p.get("search.packages", p.get("packages", null));
|
||||
packages = getSearchJarsPackages(packagesProp);
|
||||
}
|
||||
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", true);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", true);
|
||||
collectQueryStatsByNode = p.getBoolean("collectQueryStatsByNode", collectQueryStatsByNode);
|
||||
collectQueryOrigins = p.getBoolean("collectQueryOrigins", collectQueryOrigins);
|
||||
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", true);
|
||||
updateChangesOnly = p.getBoolean("updateChangesOnly", updateChangesOnly);
|
||||
|
||||
boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", true);
|
||||
boolean defaultDeleteMissingChildren = p.getBoolean("defaultDeleteMissingChildren", updatesDeleteMissingChildren);
|
||||
updatesDeleteMissingChildren = p.getBoolean("updatesDeleteMissingChildren", defaultDeleteMissingChildren);
|
||||
|
||||
boolean batchMode = p.getBoolean("batch.mode", false);
|
||||
boolean batchMode = p.getBoolean("batch.mode", persistBatching);
|
||||
persistBatching = p.getBoolean("persistBatching", batchMode);
|
||||
|
||||
int batchSize = p.getInt("batch.size", 20);
|
||||
int batchSize = p.getInt("batch.size", persistBatchSize);
|
||||
persistBatchSize = p.getInt("persistBatchSize", batchSize);
|
||||
|
||||
persistenceContextScope = PersistenceContextScope.valueOf(p.get("persistenceContextScope","TRANSACTION"));
|
||||
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", null);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", 20);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", null);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", null);
|
||||
databasePlatformName = p.get("databasePlatformName", null);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", false);
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", false);
|
||||
dataSourceJndiName = p.get("dataSourceJndiName", dataSourceJndiName);
|
||||
databaseSequenceBatchSize = p.getInt("databaseSequenceBatchSize", databaseSequenceBatchSize);
|
||||
databaseBooleanTrue = p.get("databaseBooleanTrue", databaseBooleanTrue);
|
||||
databaseBooleanFalse = p.get("databaseBooleanFalse", databaseBooleanFalse);
|
||||
databasePlatformName = p.get("databasePlatformName", databasePlatformName);
|
||||
uuidStoreAsBinary = p.getBoolean("uuidStoreAsBinary", uuidStoreAsBinary);
|
||||
localTimeWithNanos = p.getBoolean("localTimeWithNanos", localTimeWithNanos);
|
||||
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", 1);
|
||||
queryBatchSize = p.getInt("queryBatchSize", DEFAULT_QUERY_BATCH_SIZE);
|
||||
lazyLoadBatchSize = p.getInt("lazyLoadBatchSize", lazyLoadBatchSize);
|
||||
queryBatchSize = p.getInt("queryBatchSize", queryBatchSize);
|
||||
|
||||
String jsonDateTimeFormat = p.get("jsonDateTime", null);
|
||||
if (jsonDateTimeFormat != null) {
|
||||
@@ -1464,27 +1734,27 @@ public class ServerConfig {
|
||||
jsonDateTime = JsonConfig.DateTime.MILLIS;
|
||||
}
|
||||
|
||||
ddlGenerate = p.getBoolean("ddl.generate", false);
|
||||
ddlRun = p.getBoolean("ddl.run", false);
|
||||
ddlGenerate = p.getBoolean("ddl.generate", ddlGenerate);
|
||||
ddlRun = p.getBoolean("ddl.run", ddlRun);
|
||||
|
||||
classes = getClasses(p);
|
||||
}
|
||||
|
||||
private NamingConvention createNamingConvention(PropertySource p) {
|
||||
private NamingConvention createNamingConvention(PropertiesWrapper properties) {
|
||||
|
||||
NamingConvention nc = createInstance(p, NamingConvention.class, "namingconvention");
|
||||
NamingConvention nc = createInstance(properties, NamingConvention.class, "namingconvention");
|
||||
if (nc == null) {
|
||||
return null;
|
||||
}
|
||||
if (nc instanceof AbstractNamingConvention) {
|
||||
AbstractNamingConvention anc = (AbstractNamingConvention) nc;
|
||||
String v = p.get("namingConvention.useForeignKeyPrefix", null);
|
||||
String v = properties.get("namingConvention.useForeignKeyPrefix", null);
|
||||
if (v != null) {
|
||||
boolean useForeignKeyPrefix = Boolean.valueOf(v);
|
||||
anc.setUseForeignKeyPrefix(useForeignKeyPrefix);
|
||||
}
|
||||
|
||||
String sequenceFormat = p.get("namingConvention.sequenceFormat", null);
|
||||
String sequenceFormat = properties.get("namingConvention.sequenceFormat", null);
|
||||
if (sequenceFormat != null) {
|
||||
anc.setSequenceFormat(sequenceFormat);
|
||||
}
|
||||
@@ -1495,20 +1765,20 @@ public class ServerConfig {
|
||||
/**
|
||||
* Build the list of classes from the comma delimited string.
|
||||
*
|
||||
* @param p
|
||||
* the p
|
||||
* @param properties
|
||||
* the properties
|
||||
*
|
||||
* @return the classes
|
||||
*/
|
||||
private ArrayList<Class<?>> getClasses(PropertySource p) {
|
||||
private List<Class<?>> getClasses(PropertiesWrapper properties) {
|
||||
|
||||
String classNames = p.get("classes", null);
|
||||
String classNames = properties.get("classes", null);
|
||||
if (classNames == null) {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
|
||||
String[] split = classNames.split("[ ,;]");
|
||||
for (int i = 0; i < split.length; i++) {
|
||||
@@ -1538,5 +1808,4 @@ public class ServerConfig {
|
||||
}
|
||||
return hitList;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,6 +72,10 @@ public class DatabasePlatform {
|
||||
*/
|
||||
protected String name = "generic";
|
||||
|
||||
protected String columnAliasPrefix = "c";
|
||||
|
||||
protected String tableAliasPlaceHolder = "${ta}";
|
||||
|
||||
/**
|
||||
* Use a BackTick ` at the beginning and end of table or column names that you
|
||||
* want to use quoted identifiers for. The backticks get converted to the
|
||||
@@ -166,6 +170,34 @@ public class DatabasePlatform {
|
||||
return dbDdlSyntax;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column alias prefix.
|
||||
*/
|
||||
public String getColumnAliasPrefix() {
|
||||
return columnAliasPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the column alias prefix.
|
||||
*/
|
||||
public void setColumnAliasPrefix(String columnAliasPrefix) {
|
||||
this.columnAliasPrefix = columnAliasPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the table alias placeholder.
|
||||
*/
|
||||
public String getTableAliasPlaceHolder() {
|
||||
return tableAliasPlaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the table alias placeholder.
|
||||
*/
|
||||
public void setTableAliasPlaceHolder(String tableAliasPlaceHolder) {
|
||||
this.tableAliasPlaceHolder = tableAliasPlaceHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the close quote for quoted identifiers.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@@ -14,15 +13,13 @@ public class H2Platform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "h2";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
this.likeClause = "like ? escape''";
|
||||
// like ? escape'' not working in the latest version H2 so just using no
|
||||
// escape clause for now noting that backslash is an escape char for like in H2
|
||||
this.likeClause = "like ?";
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
boolean useIdentity = GlobalProperties.getBoolean("ebean.h2platform.useIdentity", false);
|
||||
|
||||
IdType idType = useIdentity ? IdType.IDENTITY : IdType.SEQUENCE;
|
||||
this.dbIdentity.setIdType(idType);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import java.sql.Types;
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* H2 specific platform.
|
||||
@@ -16,14 +14,7 @@ public class HsqldbPlatform extends DatabasePlatform {
|
||||
super();
|
||||
this.name = "hsqldb";
|
||||
this.dbEncrypt = new H2DbEncrypt();
|
||||
|
||||
// only support getGeneratedKeys with non-batch JDBC
|
||||
// so generally use SEQUENCE instead of IDENTITY for H2
|
||||
boolean useIdentity = GlobalProperties.getBoolean("ebean.hsqldb.useIdentity", true);
|
||||
|
||||
IdType idType = useIdentity ? IdType.IDENTITY : IdType.SEQUENCE;
|
||||
this.dbIdentity.setIdType(idType);
|
||||
|
||||
this.dbIdentity.setIdType(IdType.IDENTITY);
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
this.dbIdentity.setSupportsIdentity(true);
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
/**
|
||||
* Oracle encryption support.
|
||||
*
|
||||
@@ -48,12 +46,19 @@ import com.avaje.ebean.config.GlobalProperties;
|
||||
public class Oracle10DbEncrypt extends AbstractDbEncrypt {
|
||||
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt.
|
||||
* Constructs the Oracle10DbEncrypt with default encrypt and decrypt stored procedures.
|
||||
*/
|
||||
public Oracle10DbEncrypt() {
|
||||
this("eb_encrypt", "eb_decrypt");
|
||||
}
|
||||
|
||||
String encryptfunction = GlobalProperties.get("ebean.oracle.encryptfunction", "eb_encrypt");
|
||||
String decryptfunction = GlobalProperties.get("ebean.oracle.decryptfunction", "eb_decrypt");
|
||||
/**
|
||||
* Constructs the Oracle10DbEncrypt specifying encrypt and decrypt stored procedures.
|
||||
*
|
||||
* @param encryptfunction the encrypt stored procedure
|
||||
* @param decryptfunction the decrypt stored procedure
|
||||
*/
|
||||
public Oracle10DbEncrypt(String encryptfunction, String decryptfunction) {
|
||||
|
||||
this.varcharEncryptFunction = new OraVarcharFunction(encryptfunction, decryptfunction);
|
||||
this.dateEncryptFunction = new OraDateFunction(encryptfunction, decryptfunction);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Types;
|
||||
@@ -27,12 +26,7 @@ public class Postgres8Platform extends DatabasePlatform {
|
||||
this.dbIdentity.setIdType(IdType.SEQUENCE);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
if (colAlias == null) {
|
||||
// Postgres requires the "as" keyword for column alias
|
||||
GlobalProperties.put("ebean.columnAliasPrefix", "as c");
|
||||
}
|
||||
|
||||
this.columnAliasPrefix = "as c";
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package com.avaje.ebean.config.dbplatform;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
@@ -38,11 +36,7 @@ public class PostgresPlatform extends DatabasePlatform {
|
||||
this.dbIdentity.setSupportsGetGeneratedKeys(true);
|
||||
this.dbIdentity.setSupportsSequence(true);
|
||||
|
||||
String colAlias = GlobalProperties.get("ebean.columnAliasPrefix", null);
|
||||
if (colAlias == null) {
|
||||
// Postgres requires the "as" keyword for column alias
|
||||
GlobalProperties.put("ebean.columnAliasPrefix", "as c");
|
||||
}
|
||||
this.columnAliasPrefix = "as c";
|
||||
|
||||
this.openQuote = "\"";
|
||||
this.closeQuote = "\"";
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
package com.avaje.ebeaninternal.api;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.DeleteByIdMap;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexInvalidate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Holds information for a transaction. There is one TransactionEvent instance
|
||||
@@ -25,180 +17,107 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class TransactionEvent implements Serializable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransactionEvent.class);
|
||||
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
private static final long serialVersionUID = 7230903304106097120L;
|
||||
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
/**
|
||||
* Flag indicating this is a local transaction (not from another server in
|
||||
* the cluster).
|
||||
*/
|
||||
private transient boolean local;
|
||||
|
||||
private boolean invalidateAll;
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private TransactionEventTable eventTables;
|
||||
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
private transient TransactionEventBeans eventBeans;
|
||||
|
||||
private transient List<BeanDelta> beanDeltas;
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient DeleteByIdMap deleteByIdMap;
|
||||
|
||||
private transient Set<IndexInvalidate> indexInvalidations;
|
||||
|
||||
private transient Set<String> pauseIndexInvalidate;
|
||||
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this to true to invalidate all table dependent cached objects.
|
||||
*/
|
||||
public void setInvalidateAll(boolean isInvalidateAll) {
|
||||
this.invalidateAll = isInvalidateAll;
|
||||
}
|
||||
/**
|
||||
* Create the TransactionEvent, one per Transaction.
|
||||
*/
|
||||
public TransactionEvent() {
|
||||
this.local = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if all table states should be invalidated. This will cause
|
||||
* all cached objects to be invalidated.
|
||||
*/
|
||||
public boolean isInvalidateAll() {
|
||||
return invalidateAll;
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporarily pause/ignore any index invalidation for this bean type.
|
||||
*/
|
||||
public void pauseIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate == null){
|
||||
pauseIndexInvalidate = new HashSet<String>();
|
||||
}
|
||||
pauseIndexInvalidate.add(beanType.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume listening for index invalidation for this bean type.
|
||||
*/
|
||||
public void resumeIndexInvalidate(Class<?> beanType) {
|
||||
if (pauseIndexInvalidate != null){
|
||||
pauseIndexInvalidate.remove(beanType.getName());
|
||||
}
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an IndexInvalidation notices to the transaction.
|
||||
*/
|
||||
public void addIndexInvalidate(IndexInvalidate indexEvent){
|
||||
if (pauseIndexInvalidate != null && pauseIndexInvalidate.contains(indexEvent.getIndexName())){
|
||||
logger.debug("--- IGNORE Invalidate on "+indexEvent.getIndexName());
|
||||
return;
|
||||
}
|
||||
if (indexInvalidations == null){
|
||||
indexInvalidations = new HashSet<IndexInvalidate>();
|
||||
}
|
||||
indexInvalidations.add(indexEvent);
|
||||
}
|
||||
|
||||
public void addDeleteById(BeanDescriptor<?> desc, Object id){
|
||||
if (deleteByIdMap == null){
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
deleteByIdMap.add(desc, id);
|
||||
}
|
||||
|
||||
public void addDeleteByIdList(BeanDescriptor<?> desc, List<Object> idList) {
|
||||
if (deleteByIdMap == null) {
|
||||
deleteByIdMap = new DeleteByIdMap();
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
deleteByIdMap.addList(desc, idList);
|
||||
}
|
||||
|
||||
public DeleteByIdMap getDeleteByIdMap() {
|
||||
return deleteByIdMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes) {
|
||||
if (eventTables == null) {
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void addBeanDelta(BeanDelta delta) {
|
||||
if (beanDeltas == null) {
|
||||
beanDeltas = new ArrayList<BeanDelta>();
|
||||
}
|
||||
beanDeltas.add(delta);
|
||||
public void add(TransactionEventTable table) {
|
||||
if (eventTables == null) {
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
public List<BeanDelta> getBeanDeltas() {
|
||||
return beanDeltas;
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)) {
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this was a local transaction. Returns false if this
|
||||
* transaction originated on another server in the cluster.
|
||||
*/
|
||||
public boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For BeanListeners the requests they are interested in.
|
||||
*/
|
||||
public TransactionEventBeans getEventBeans() {
|
||||
return eventBeans;
|
||||
}
|
||||
|
||||
public TransactionEventTable getEventTables() {
|
||||
return eventTables;
|
||||
}
|
||||
|
||||
public Set<IndexInvalidate> getIndexInvalidations() {
|
||||
return indexInvalidations;
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache() {
|
||||
if (eventBeans != null) {
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
|
||||
public void add(String tableName, boolean inserts, boolean updates, boolean deletes){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(tableName, inserts, updates, deletes);
|
||||
}
|
||||
|
||||
public void add(TransactionEventTable table){
|
||||
if (eventTables == null){
|
||||
eventTables = new TransactionEventTable();
|
||||
}
|
||||
eventTables.add(table);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a inserted updated or deleted bean to the event.
|
||||
*/
|
||||
public void add(PersistRequestBean<?> request) {
|
||||
|
||||
if (request.isNotify(this)){
|
||||
// either a BeanListener or Cache is interested
|
||||
if (eventBeans == null) {
|
||||
eventBeans = new TransactionEventBeans();
|
||||
}
|
||||
eventBeans.add(request);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the cache of bean changes.
|
||||
* <p>
|
||||
* This returns the TransactionEventTable so that if any
|
||||
* general table changes can also be used to invalidate
|
||||
* parts of the cache.
|
||||
* </p>
|
||||
*/
|
||||
public void notifyCache(){
|
||||
if (eventBeans != null){
|
||||
eventBeans.notifyCache();
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
if (deleteByIdMap != null) {
|
||||
deleteByIdMap.notifyCache();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public final class TransactionEventTable implements Serializable {
|
||||
private boolean update;
|
||||
private boolean delete;
|
||||
|
||||
private TableIUD(String table, boolean insert, boolean update, boolean delete){
|
||||
public TableIUD(String table, boolean insert, boolean update, boolean delete){
|
||||
this.table = table;
|
||||
this.insert = insert;
|
||||
this.update = update;
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.ObjectInputStream;
|
||||
|
||||
public class AutoFetchManagerFactory {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(AutoFetchManagerFactory.class);
|
||||
@@ -37,7 +35,7 @@ public class AutoFetchManagerFactory {
|
||||
|
||||
AutoFetchManager autoFetchManager = null;
|
||||
|
||||
boolean readFile = GlobalProperties.getBoolean("autofetch.readfromfile", true);
|
||||
boolean readFile = !"false".equalsIgnoreCase(System.getProperty("autofetch.readfromfile"));
|
||||
if (readFile) {
|
||||
autoFetchManager = deserializeAutoFetch(autoFetchFile);
|
||||
}
|
||||
|
||||
+14
-10
@@ -22,6 +22,8 @@ import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The manager of all the usage/query statistics as well as the tuned fetch
|
||||
@@ -29,6 +31,8 @@ import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
*/
|
||||
public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultAutoFetchManager.class);
|
||||
|
||||
private static final long serialVersionUID = -6826119882781771722L;
|
||||
|
||||
private final String statisticsMonitor = new String();
|
||||
@@ -551,16 +555,16 @@ public class DefaultAutoFetchManager implements AutoFetchManager, Serializable {
|
||||
|
||||
Statistics stats = getQueryPointStats(origin);
|
||||
|
||||
if (logging.isTraceUsageCollection()){
|
||||
System.out.println("... NodeUsageCollector "+usageCollector);
|
||||
}
|
||||
|
||||
stats.collectUsageInfo(usageCollector);
|
||||
|
||||
if (logging.isTraceUsageCollection()){
|
||||
System.out.println("stats\n"+stats);
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... NodeUsageCollector " + usageCollector);
|
||||
}
|
||||
|
||||
stats.collectUsageInfo(usageCollector);
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("stats\n" + stats);
|
||||
}
|
||||
}
|
||||
|
||||
private Statistics getQueryPointStats(ObjectGraphOrigin originQueryPoint) {
|
||||
synchronized (statisticsMonitor) {
|
||||
|
||||
+5
-15
@@ -1,14 +1,12 @@
|
||||
package com.avaje.ebeaninternal.server.autofetch;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Handles the logging aspects for the DefaultAutoFetchListener.
|
||||
@@ -23,15 +21,12 @@ public class DefaultAutoFetchManagerLogging {
|
||||
|
||||
private final DefaultAutoFetchManager manager;
|
||||
|
||||
private final boolean traceUsageCollection;
|
||||
|
||||
private final int updateFreqInSecs;
|
||||
|
||||
public DefaultAutoFetchManagerLogging(ServerConfig serverConfig, DefaultAutoFetchManager profileListener) {
|
||||
|
||||
this.manager = profileListener;
|
||||
this.traceUsageCollection = GlobalProperties.getBoolean("ebean.autofetch.traceUsageCollection", false);
|
||||
this.updateFreqInSecs = serverConfig.getAutofetchConfig().getProfileUpdateFrequency();
|
||||
this.updateFreqInSecs = serverConfig.getAutofetchConfig().getProfileUpdateFrequency();
|
||||
}
|
||||
|
||||
public void init(SpiEbeanServer ebeanServer) {
|
||||
@@ -69,9 +64,4 @@ public class DefaultAutoFetchManagerLogging {
|
||||
String msg = tunedFetch.getLogOutput(null);
|
||||
logger.debug(msg);
|
||||
}
|
||||
|
||||
public boolean isTraceUsageCollection() {
|
||||
return traceUsageCollection;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ import java.io.DataOutputStream;
|
||||
* be common for many Ack, Resend and Control messages to all be contained in a
|
||||
* single packet.
|
||||
* </p>
|
||||
*
|
||||
* @author rbygrave
|
||||
*
|
||||
*/
|
||||
public class BinaryMessage {
|
||||
|
||||
@@ -28,8 +25,7 @@ public class BinaryMessage {
|
||||
public static final int TYPE_TABLEIUD = 2;
|
||||
public static final int TYPE_BEANDELTA = 3;
|
||||
public static final int TYPE_BEANPATHUPDATE = 4;
|
||||
public static final int TYPE_INDEX_INVALIDATE = 6;
|
||||
public static final int TYPE_INDEX = 7;
|
||||
|
||||
public static final int TYPE_MSGACK = 8;
|
||||
public static final int TYPE_MSGRESEND = 9;
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ package com.avaje.ebeaninternal.server.cluster;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.avaje.ebean.EbeanServer;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebeaninternal.server.cluster.mcast.McastClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.socket.SocketClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
@@ -26,41 +25,36 @@ public class ClusterManager {
|
||||
|
||||
private boolean started;
|
||||
|
||||
public ClusterManager() {
|
||||
public ClusterManager(ContainerConfig containerConfig) {
|
||||
|
||||
String clusterType = GlobalProperties.get("ebean.cluster.type", null);
|
||||
if (clusterType == null || clusterType.trim().length() == 0) {
|
||||
// not clustering this instance
|
||||
this.broadcast = null;
|
||||
|
||||
} else {
|
||||
|
||||
try {
|
||||
if ("mcast".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new McastClusterManager();
|
||||
|
||||
} else if ("socket".equalsIgnoreCase(clusterType)) {
|
||||
this.broadcast = new SocketClusterBroadcast();
|
||||
|
||||
} else {
|
||||
logger.info("Clustering using [" + clusterType + "]");
|
||||
this.broadcast = (ClusterBroadcast) ClassUtil.newInstance(clusterType);
|
||||
ContainerConfig.ClusterMode mode = containerConfig.getMode();
|
||||
try {
|
||||
switch (mode) {
|
||||
case SOCKET: {
|
||||
this.broadcast = new SocketClusterBroadcast(containerConfig);
|
||||
break;
|
||||
}
|
||||
case MULTICAST: {
|
||||
this.broadcast = new McastClusterManager(containerConfig);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
this.broadcast = null;
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
String msg = "Error initialising ClusterManager type [" + clusterType + "]";
|
||||
logger.error(msg, e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error initialising ClusterManager type [" + mode + "]", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerServer(EbeanServer server) {
|
||||
synchronized (monitor) {
|
||||
serverMap.put(server.getName(), server);
|
||||
if (!started) {
|
||||
startup();
|
||||
}
|
||||
serverMap.put(server.getName(), server);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanDelta;
|
||||
import com.avaje.ebeaninternal.server.transaction.BeanPersistIds;
|
||||
import com.avaje.ebeaninternal.server.transaction.IndexEvent;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
|
||||
/**
|
||||
@@ -16,7 +15,6 @@ import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
* Due to the hard limit for UDP packet sizes a RemoteTransactionEvent
|
||||
* is actually broken up into smaller messages.
|
||||
* </p>
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class PacketTransactionEvent extends Packet {
|
||||
|
||||
@@ -63,10 +61,6 @@ public class PacketTransactionEvent extends Packet {
|
||||
event.addBeanDelta(BeanDelta.readBinaryMessage(server, dataInput));
|
||||
break;
|
||||
|
||||
case BinaryMessage.TYPE_INDEX:
|
||||
event.addIndexEvent(IndexEvent.readBinaryMessage(dataInput));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid Transaction msgType "+msgType);
|
||||
}
|
||||
|
||||
+41
-36
@@ -7,49 +7,54 @@ import java.util.List;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Mechanism to convert RemoteTransactionEvent to/from byte[] content.
|
||||
*/
|
||||
public abstract class SerialiseTransactionHelper {
|
||||
|
||||
private final PacketWriter packetWriter;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SerialiseTransactionHelper.class);
|
||||
|
||||
public SerialiseTransactionHelper() {
|
||||
packetWriter = new PacketWriter(Integer.MAX_VALUE);
|
||||
private final PacketWriter packetWriter;
|
||||
|
||||
public SerialiseTransactionHelper() {
|
||||
packetWriter = new PacketWriter(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public abstract SpiEbeanServer getEbeanServer(String serverName);
|
||||
|
||||
/**
|
||||
* Convert the RemoteTransactionEvent to byte[] content.
|
||||
*/
|
||||
public DataHolder createDataHolder(RemoteTransactionEvent transEvent) throws IOException {
|
||||
|
||||
List<Packet> packetList = packetWriter.write(transEvent);
|
||||
if (packetList.size() != 1) {
|
||||
throw new RuntimeException("Always expecting 1 Packet but got " + packetList.size());
|
||||
}
|
||||
byte[] data = packetList.get(0).getBytes();
|
||||
return new DataHolder(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the byte[] content to RemoteTransactionEvent.
|
||||
*/
|
||||
public RemoteTransactionEvent read(DataHolder dataHolder) throws IOException {
|
||||
|
||||
ByteArrayInputStream bi = new ByteArrayInputStream(dataHolder.getData());
|
||||
DataInputStream dataInput = new DataInputStream(bi);
|
||||
|
||||
Packet header = Packet.readHeader(dataInput);
|
||||
|
||||
SpiEbeanServer server = getEbeanServer(header.getServerName());
|
||||
if (server == null) {
|
||||
logger.error("server [{}] not found/registered?", header.getServerName());
|
||||
}
|
||||
|
||||
public abstract SpiEbeanServer getEbeanServer(String serverName);
|
||||
|
||||
/**
|
||||
* Convert the RemoteTransactionEvent to byte[] content.
|
||||
*/
|
||||
public DataHolder createDataHolder(RemoteTransactionEvent transEvent) throws IOException {
|
||||
|
||||
List<Packet> packetList = packetWriter.write(transEvent);
|
||||
if (packetList.size() != 1) {
|
||||
throw new RuntimeException("Always expecting 1 Packet but got " + packetList.size());
|
||||
}
|
||||
byte[] data = packetList.get(0).getBytes();
|
||||
return new DataHolder(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the byte[] content to RemoteTransactionEvent.
|
||||
*/
|
||||
public RemoteTransactionEvent read(DataHolder dataHolder) throws IOException {
|
||||
|
||||
ByteArrayInputStream bi = new ByteArrayInputStream(dataHolder.getData());
|
||||
DataInputStream dataInput = new DataInputStream(bi);
|
||||
|
||||
Packet header = Packet.readHeader(dataInput);
|
||||
|
||||
SpiEbeanServer server = getEbeanServer(header.getServerName());
|
||||
|
||||
PacketTransactionEvent tranEventPacket = PacketTransactionEvent.forRead(header, server);
|
||||
tranEventPacket.read(dataInput);
|
||||
|
||||
return tranEventPacket.getEvent();
|
||||
|
||||
}
|
||||
PacketTransactionEvent tranEventPacket = PacketTransactionEvent.forRead(header, server);
|
||||
tranEventPacket.read(dataInput);
|
||||
return tranEventPacket.getEvent();
|
||||
}
|
||||
}
|
||||
|
||||
+494
-515
File diff suppressed because it is too large
Load Diff
@@ -19,6 +19,12 @@
|
||||
*/
|
||||
package com.avaje.ebeaninternal.server.cluster.mcast;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
import com.avaje.ebeaninternal.server.cluster.PacketTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
@@ -28,13 +34,6 @@ import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.MulticastSocket;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.Packet;
|
||||
import com.avaje.ebeaninternal.server.cluster.PacketTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Listens for Incoming packets.
|
||||
*
|
||||
@@ -56,8 +55,6 @@ public class McastListener implements Runnable {
|
||||
|
||||
private final InetAddress group;
|
||||
|
||||
private final boolean debugIgnore;
|
||||
|
||||
private DatagramPacket pack;
|
||||
|
||||
private byte[] receiveBuffer;
|
||||
@@ -73,8 +70,6 @@ public class McastListener implements Runnable {
|
||||
int bufferSize, int timeout, String localSenderHostPort,
|
||||
boolean disableLoopback, int ttl, InetAddress mcastBindAddress) {
|
||||
|
||||
this.debugIgnore = GlobalProperties.getBoolean("ebean.debug.mcast.ignore", false);
|
||||
|
||||
this.owner = owner;
|
||||
this.packetControl = packetControl;
|
||||
this.localSenderHostPort = localSenderHostPort;
|
||||
@@ -96,7 +91,7 @@ public class McastListener implements Runnable {
|
||||
this.sock.setSoTimeout(timeout);
|
||||
|
||||
if (disableLoopback){
|
||||
sock.setLoopbackMode(disableLoopback);
|
||||
sock.setLoopbackMode(true);
|
||||
}
|
||||
|
||||
if (mcastBindAddress != null) {
|
||||
@@ -173,7 +168,7 @@ public class McastListener implements Runnable {
|
||||
String senderHostPort = senderAddr.getAddress().getHostAddress()+":"+senderAddr.getPort();
|
||||
|
||||
if (senderHostPort.equals(localSenderHostPort)){
|
||||
if (debugIgnore || logger.isDebugEnabled()){
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.info("Ignoring message as sent by localSender: "+localSenderHostPort);
|
||||
}
|
||||
} else {
|
||||
@@ -195,7 +190,7 @@ public class McastListener implements Runnable {
|
||||
boolean processThisPacket = ackMsg || packetControl.isProcessPacket(senderHostPort, header.getPacketId());
|
||||
|
||||
if (!processThisPacket){
|
||||
if (debugIgnore || logger.isDebugEnabled()){
|
||||
if (logger.isTraceEnabled()){
|
||||
logger.info("Already processed packet: "+header.getPacketId()+" type:"+header.getPacketType()+" len:"+data.length);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -21,15 +21,18 @@ class RequestProcessor implements Runnable {
|
||||
private final Socket clientSocket;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
/**
|
||||
|
||||
private final String hostPort;
|
||||
|
||||
/**
|
||||
* Create including the Listener (used to lookup the Request Handler) and
|
||||
* the socket itself.
|
||||
*/
|
||||
public RequestProcessor(SocketClusterBroadcast owner, Socket clientSocket) {
|
||||
this.clientSocket = clientSocket;
|
||||
this.owner = owner;
|
||||
}
|
||||
this.hostPort = owner.getHostPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* This will parse out the command. Lookup the appropriate Handler and
|
||||
@@ -39,22 +42,20 @@ class RequestProcessor implements Runnable {
|
||||
*/
|
||||
public void run() {
|
||||
try {
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
|
||||
while(true){
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
sc.disconnect();
|
||||
|
||||
} catch (IOException e) {
|
||||
logger.error(null, e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
logger.error(null, e);
|
||||
logger.trace("start listening for cluster messages");
|
||||
SocketConnection sc = new SocketConnection(clientSocket);
|
||||
while (true) {
|
||||
if (owner.process(sc)) {
|
||||
// got the offline message or timeout
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.trace("disconnecting: {}", hostPort);
|
||||
sc.disconnect();
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("Error listening for messages - "+owner.getHostPort(), e);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
@@ -35,6 +35,10 @@ class SocketClient {
|
||||
this.hostPort = address.getHostName()+":"+address.getPort();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return address.toString();
|
||||
}
|
||||
|
||||
public String getHostPort() {
|
||||
return hostPort;
|
||||
}
|
||||
|
||||
+217
-209
@@ -1,248 +1,256 @@
|
||||
package com.avaje.ebeaninternal.server.cluster.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ContainerConfig;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterBroadcast;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.cluster.DataHolder;
|
||||
import com.avaje.ebeaninternal.server.cluster.SerialiseTransactionHelper;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.transaction.RemoteTransactionEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
* Broadcast messages across the cluster using sockets.
|
||||
*/
|
||||
public class SocketClusterBroadcast implements ClusterBroadcast {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterBroadcast.class);
|
||||
|
||||
private final SocketClient local;
|
||||
|
||||
private final HashMap<String,SocketClient> clientMap;
|
||||
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
private SocketClient[] members;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterBroadcast.class);
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
private final SocketClient local;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
|
||||
public SocketClusterBroadcast( ){
|
||||
|
||||
String localHostPort = GlobalProperties.get("ebean.cluster.local", null);
|
||||
String members = GlobalProperties.get("ebean.cluster.members", null);
|
||||
private final HashMap<String, SocketClient> clientMap;
|
||||
|
||||
logger.info("Clustering using Sockets local["+localHostPort+"] members["+members+"]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
String[] memArray = StringHelper.delimitedToArray(members, ",", false);
|
||||
for (int i = 0; i < memArray.length; i++) {
|
||||
InetSocketAddress member = parseFullName(memArray[i]);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
private final SocketClusterListener listener;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
private SocketClient[] members;
|
||||
|
||||
private ClusterManager clusterManager;
|
||||
|
||||
private final TxnSerialiseHelper txnSerialiseHelper = new TxnSerialiseHelper();
|
||||
|
||||
private final AtomicInteger txnOutgoing = new AtomicInteger();
|
||||
private final AtomicInteger txnIncoming = new AtomicInteger();
|
||||
|
||||
public SocketClusterBroadcast(ContainerConfig containerConfig) {
|
||||
|
||||
ContainerConfig.SocketConfig socketConfig = containerConfig.getSocketConfig();
|
||||
|
||||
String localHostPort = socketConfig.getLocalHostPort();
|
||||
List<String> members = socketConfig.getMembers();
|
||||
|
||||
logger.info("Clustering using Sockets local[" + localHostPort + "] members[" + members + "]");
|
||||
|
||||
this.local = new SocketClient(parseFullName(localHostPort));
|
||||
this.clientMap = new HashMap<String, SocketClient>();
|
||||
|
||||
for (String memberHostPort : members) {
|
||||
InetSocketAddress member = parseFullName(memberHostPort);
|
||||
SocketClient client = new SocketClient(member);
|
||||
if (!local.getHostPort().equalsIgnoreCase(client.getHostPort())) {
|
||||
// don't add the local one ...
|
||||
clientMap.put(client.getHostPort(), client);
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
this.members = clientMap.values().toArray(new SocketClient[clientMap.size()]);
|
||||
this.listener = new SocketClusterListener(this, local.getPort(), socketConfig.getCoreThreads(), socketConfig.getMaxThreads(), socketConfig.getThreadPoolName());
|
||||
}
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
|
||||
String msg = "Cluster Member ["+members[i].getHostPort()+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
}
|
||||
public String getHostPort() {
|
||||
return local.getHostPort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current status of this instance.
|
||||
*/
|
||||
public SocketClusterStatus getStatus() {
|
||||
|
||||
// count of online members
|
||||
int currentGroupSize = 0;
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
if (members[i].isOnline()) {
|
||||
++currentGroupSize;
|
||||
}
|
||||
}
|
||||
int txnIn = txnIncoming.get();
|
||||
int txnOut = txnOutgoing.get();
|
||||
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
String msg = "Cluster Member ["+fullName+"] online["+online+"]";
|
||||
logger.info(msg);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
return new SocketClusterStatus(currentGroupSize, txnIn, txnOut);
|
||||
}
|
||||
|
||||
public void startup(ClusterManager clusterManager) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
try {
|
||||
listener.startListening();
|
||||
register();
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new PersistenceException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
public void shutdown() {
|
||||
deregister();
|
||||
listener.shutdown();
|
||||
}
|
||||
|
||||
try {
|
||||
// alternative would be to connect/disconnect here
|
||||
// but prefer to use keepalive
|
||||
client.send(msg);
|
||||
|
||||
} catch (Exception ex){
|
||||
logger.error("Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Register with all the other members of the Cluster.
|
||||
*/
|
||||
private void register() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), true);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
boolean online = members[i].register(h);
|
||||
logger.info("Cluster Member [{}] online[{}]", members[i].getHostPort(), online);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e){
|
||||
String msg = "Error sending RemoteTransactionEvent "+remoteTransEvent+" to cluster members.";
|
||||
logger.error(msg, e);
|
||||
}
|
||||
protected void setMemberOnline(String fullName, boolean online) throws IOException {
|
||||
synchronized (clientMap) {
|
||||
logger.info("Cluster Member [{}] online[{}]", fullName, online);
|
||||
SocketClient member = clientMap.get(fullName);
|
||||
member.setOnline(online);
|
||||
}
|
||||
}
|
||||
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
private void send(SocketClient client, SocketClusterMessage msg) {
|
||||
|
||||
/**
|
||||
* Process a Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
try {
|
||||
// alternative would be to connect/disconnect here but prefer to use keepalive
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... send to member {} broadcast msg: {}", client, msg);
|
||||
}
|
||||
client.send(msg);
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage)request.readObject();
|
||||
|
||||
if (h.isRegisterEvent()){
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent() && !h.isRegister()){
|
||||
// instance shutting down
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
String msg = "Timeout waiting for message";
|
||||
logger.info(msg, e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex){
|
||||
logger.info("Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.error("Error sending message", ex);
|
||||
try {
|
||||
client.reconnect();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error trying to reconnect", ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in "+hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex){
|
||||
throw new RuntimeException("Error parsing ["+hostAndPort+"] for the form [host:port]", ex);
|
||||
}
|
||||
/**
|
||||
* Send the payload to all the members of the cluster.
|
||||
*/
|
||||
public void broadcast(RemoteTransactionEvent remoteTransEvent) {
|
||||
try {
|
||||
txnOutgoing.incrementAndGet();
|
||||
DataHolder dataHolder = txnSerialiseHelper.createDataHolder(remoteTransEvent);
|
||||
SocketClusterMessage msg = SocketClusterMessage.transEvent(dataHolder);
|
||||
broadcast(msg);
|
||||
} catch (Exception e) {
|
||||
logger.error("Error sending RemoteTransactionEvent " + remoteTransEvent + " to cluster members.", e);
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer)clusterManager.getServer(serverName);
|
||||
}
|
||||
protected void broadcast(SocketClusterMessage msg) {
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... broadcast msg: "+msg);
|
||||
}
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
send(members[i], msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Leave the cluster.
|
||||
*/
|
||||
private void deregister() {
|
||||
|
||||
SocketClusterMessage h = SocketClusterMessage.register(local.getHostPort(), false);
|
||||
broadcast(h);
|
||||
for (int i = 0; i < members.length; i++) {
|
||||
members[i].disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an incoming Cluster message.
|
||||
*/
|
||||
protected boolean process(SocketConnection request) throws IOException, ClassNotFoundException {
|
||||
|
||||
try {
|
||||
SocketClusterMessage h = (SocketClusterMessage) request.readObject();
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("... received msg: {}", h);
|
||||
}
|
||||
|
||||
if (h.isRegisterEvent()) {
|
||||
setMemberOnline(h.getRegisterHost(), h.isRegister());
|
||||
|
||||
} else {
|
||||
txnIncoming.incrementAndGet();
|
||||
DataHolder dataHolder = h.getDataHolder();
|
||||
RemoteTransactionEvent transEvent = txnSerialiseHelper.read(dataHolder);
|
||||
transEvent.run();
|
||||
}
|
||||
|
||||
// instance shutting down
|
||||
return h.isRegisterEvent() && !h.isRegister();
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
logger.info("Timeout waiting for message", e);
|
||||
try {
|
||||
request.disconnect();
|
||||
} catch (IOException ex) {
|
||||
logger.info("Error disconnecting after timeout", ex);
|
||||
}
|
||||
return true;
|
||||
|
||||
} catch (EOFException e) {
|
||||
logger.info("EOF disconnecting");
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
logger.info("IO Error waiting/reading message", e);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a host:port into a InetSocketAddress.
|
||||
*/
|
||||
private InetSocketAddress parseFullName(String hostAndPort) {
|
||||
|
||||
try {
|
||||
hostAndPort = hostAndPort.trim();
|
||||
int colonPos = hostAndPort.indexOf(":");
|
||||
if (colonPos == -1) {
|
||||
String msg = "No colon \":\" in " + hostAndPort;
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
String host = hostAndPort.substring(0, colonPos);
|
||||
String sPort = hostAndPort.substring(colonPos + 1, hostAndPort.length());
|
||||
int port = Integer.parseInt(sPort);
|
||||
|
||||
return new InetSocketAddress(host, port);
|
||||
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("Error parsing [" + hostAndPort + "] for the form [host:port]", ex);
|
||||
}
|
||||
}
|
||||
|
||||
class TxnSerialiseHelper extends SerialiseTransactionHelper {
|
||||
|
||||
@Override
|
||||
public SpiEbeanServer getEbeanServer(String serverName) {
|
||||
return (SpiEbeanServer) clusterManager.getServer(serverName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+99
-122
@@ -6,10 +6,10 @@ import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonThreadPool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Serverside multithreaded socket listener. Accepts connections and dispatches
|
||||
@@ -26,141 +26,118 @@ import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
*/
|
||||
class SocketClusterListener implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterListener.class);
|
||||
|
||||
/**
|
||||
* The port the SocketListener uses.
|
||||
*/
|
||||
private final int port;
|
||||
private static final Logger logger = LoggerFactory.getLogger(SocketClusterListener.class);
|
||||
|
||||
/**
|
||||
* The length of the socket accept timeout.
|
||||
*/
|
||||
private final int listenTimeout = 60000;
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
|
||||
/**
|
||||
* The server socket used to listen for requests.
|
||||
*/
|
||||
private final ServerSocket serverListenSocket;
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
|
||||
/**
|
||||
* The listening thread.
|
||||
*/
|
||||
private final Thread listenerThread;
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final DaemonThreadPool threadPool;
|
||||
|
||||
/**
|
||||
* The pool of threads that actually do the parsing execution of requests.
|
||||
*/
|
||||
private final ThreadPool threadPool;
|
||||
private final SocketClusterBroadcast owner;
|
||||
|
||||
private final SocketClusterBroadcast owner;
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
|
||||
/**
|
||||
* shutting down flag.
|
||||
*/
|
||||
boolean doingShutdown;
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
|
||||
/**
|
||||
* Whether the listening thread is busy assigning a request to a thread.
|
||||
*/
|
||||
boolean isActive;
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port, int coreThreads, int maxThreads, String poolName) {
|
||||
this.owner = owner;
|
||||
this.threadPool = new DaemonThreadPool(coreThreads, maxThreads, 60, 30, poolName);
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(60000);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
/**
|
||||
* Construct with a given thread pool name.
|
||||
*/
|
||||
public SocketClusterListener(SocketClusterBroadcast owner, int port) {
|
||||
this.owner = owner;
|
||||
this.threadPool = ThreadPool.createThreadPool("EbeanCluster");
|
||||
this.port = port;
|
||||
|
||||
try {
|
||||
this.serverListenSocket = new ServerSocket(port);
|
||||
this.serverListenSocket.setSoTimeout(listenTimeout);
|
||||
this.listenerThread = new Thread(this, "EbeanClusterListener");
|
||||
|
||||
} catch (IOException e){
|
||||
String msg = "Error starting cluster socket listener on port "+port;
|
||||
throw new RuntimeException(msg,e);
|
||||
} catch (IOException e) {
|
||||
String msg = "Error starting cluster socket listener on port " + port;
|
||||
throw new RuntimeException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
logger.trace("... startListening()");
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error shutting down listener", e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port the listener is using.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
threadPool.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start listening for requests.
|
||||
*/
|
||||
public void startListening() throws IOException {
|
||||
this.listenerThread.setDaemon(true);
|
||||
this.listenerThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown this listener.
|
||||
*/
|
||||
public void shutdown() {
|
||||
doingShutdown = true;
|
||||
try {
|
||||
if (isActive) {
|
||||
synchronized (listenerThread) {
|
||||
try {
|
||||
listenerThread.wait(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// OK to ignore as expected to Interrupt for shutdown.
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
listenerThread.interrupt();
|
||||
serverListenSocket.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error shutting down listener", e);
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.execute(request);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
|
||||
threadPool.shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a runnable and so this must be public. Don't call this externally
|
||||
* but rather call the startListening() method.
|
||||
*/
|
||||
public void run() {
|
||||
// run in loop until doingShutdown is true...
|
||||
while (!doingShutdown) {
|
||||
try {
|
||||
synchronized (listenerThread) {
|
||||
Socket clientSocket = serverListenSocket.accept();
|
||||
|
||||
isActive = true;
|
||||
|
||||
Runnable request = new RequestProcessor(owner, clientSocket);
|
||||
threadPool.assign(request, true);
|
||||
|
||||
isActive = false;
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
String msg = "doingShutdown and accept threw:"+ e.getMessage();
|
||||
logger.info(msg);
|
||||
|
||||
} else {
|
||||
logger.error(null, e);
|
||||
}
|
||||
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.debug("Possibly expected due to accept timeout?" + e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.error(null, e);
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
if (doingShutdown) {
|
||||
logger.info("doingShutdown and accept threw:" + e.getMessage());
|
||||
} else {
|
||||
logger.error("Error while listening", e);
|
||||
}
|
||||
} catch (InterruptedIOException e) {
|
||||
// this will happen when the server is very quiet.
|
||||
// that is, no requests
|
||||
logger.debug("Possibly expected due to accept timeout? {}", e.getMessage());
|
||||
|
||||
} catch (IOException e) {
|
||||
// log it and continue in the loop...
|
||||
logger.error("IOException processing cluster message", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearch;
|
||||
import com.avaje.ebeaninternal.server.util.ClassPathSearchFilter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Searches for interesting classes such as Entities, Embedded and ScalarTypes.
|
||||
*/
|
||||
@@ -20,17 +20,21 @@ public class BootupClassPathSearch {
|
||||
private final ClassLoader classLoader;
|
||||
|
||||
private final List<String> packages;
|
||||
private final List<String> jars;
|
||||
|
||||
private final List<String> jars;
|
||||
|
||||
private BootupClasses bootupClasses;
|
||||
|
||||
private final String classPathReaderClassName;
|
||||
|
||||
/**
|
||||
* Construct and search for interesting classes.
|
||||
*/
|
||||
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars) {
|
||||
public BootupClassPathSearch(ClassLoader classLoader, List<String> packages, List<String> jars, String classPathReaderClassName) {
|
||||
this.classLoader = (classLoader == null) ? getClass().getClassLoader() : classLoader;
|
||||
this.packages = packages;
|
||||
this.jars = jars;
|
||||
this.classPathReaderClassName = classPathReaderClassName;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
@@ -57,7 +61,7 @@ public class BootupClassPathSearch {
|
||||
|
||||
ClassPathSearchFilter filter = createFilter();
|
||||
|
||||
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc);
|
||||
ClassPathSearch finder = new ClassPathSearch(classLoader, filter, bc, classPathReaderClassName);
|
||||
|
||||
finder.findClasses();
|
||||
Set<String> jars = finder.getJarHits();
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Build a ServerConfig from ebean.properties.
|
||||
*/
|
||||
public class ConfigBuilder {
|
||||
|
||||
/**
|
||||
* Create a ServerConfig and load it from ebean.properties.
|
||||
*/
|
||||
public ServerConfig build(String serverName) {
|
||||
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setName(serverName);
|
||||
|
||||
config.loadFromProperties();
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -15,19 +15,21 @@ public class DefaultBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param corePoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(corePoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*
|
||||
* @param corePoolSize
|
||||
* the core size of the thread pool.
|
||||
* @param maximumPoolSize
|
||||
* the maximum pool size before jobs are queued
|
||||
* @param keepAliveSecs
|
||||
* the time in seconds idle threads are keep alive
|
||||
* @param shutdownWaitSeconds
|
||||
* the time in seconds allowed for the pool to shutdown nicely.
|
||||
* After this the pool is forced to shutdown.
|
||||
*/
|
||||
public DefaultBackgroundExecutor(int schedulePoolSize, int corePoolSize, int maximumPoolSize, long keepAliveSecs,int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = new DaemonThreadPool(corePoolSize, maximumPoolSize, keepAliveSecs, shutdownWaitSeconds, namePrefix);
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,36 +1,10 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.bean.CallStack;
|
||||
import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.bean.EntityBeanIntercept;
|
||||
import com.avaje.ebean.bean.ObjectGraphNode;
|
||||
import com.avaje.ebean.bean.PersistenceContext;
|
||||
import com.avaje.ebean.bean.*;
|
||||
import com.avaje.ebean.bean.PersistenceContext.WithOption;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
@@ -39,43 +13,16 @@ import com.avaje.ebean.meta.MetaBeanInfo;
|
||||
import com.avaje.ebean.meta.MetaInfoManager;
|
||||
import com.avaje.ebean.text.csv.CsvReader;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebeaninternal.api.LoadBeanRequest;
|
||||
import com.avaje.ebeaninternal.api.LoadManyRequest;
|
||||
import com.avaje.ebeaninternal.api.ScopeTrans;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanPlugin;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.*;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Type;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.ddl.DdlGenerator;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.DNativeQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedQuery;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployNamedUpdate;
|
||||
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.*;
|
||||
import com.avaje.ebeaninternal.server.el.ElFilter;
|
||||
import com.avaje.ebeaninternal.server.jmx.MAdminAutofetch;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import com.avaje.ebeaninternal.server.query.CQuery;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryIds;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryList;
|
||||
import com.avaje.ebeaninternal.server.query.CallableQueryRowCount;
|
||||
import com.avaje.ebeaninternal.server.query.CallableSqlQueryList;
|
||||
import com.avaje.ebeaninternal.server.query.LimitOffsetPagedList;
|
||||
import com.avaje.ebeaninternal.server.query.LimitOffsetPagingQuery;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureIds;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureList;
|
||||
import com.avaje.ebeaninternal.server.query.QueryFutureRowCount;
|
||||
import com.avaje.ebeaninternal.server.query.SqlQueryFutureList;
|
||||
import com.avaje.ebeaninternal.server.query.*;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultOrmQuery;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultOrmUpdate;
|
||||
import com.avaje.ebeaninternal.server.querydefn.DefaultRelationalQuery;
|
||||
@@ -86,6 +33,16 @@ import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper;
|
||||
import com.avaje.ebeaninternal.util.ParamTypeHelper.TypeInfo;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.management.InstanceAlreadyExistsException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
/**
|
||||
* The default server side implementation of EbeanServer.
|
||||
@@ -226,9 +183,9 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
this.collectQueryOrigins = serverConfig.isCollectQueryOrigins();
|
||||
this.collectQueryStatsByNode = serverConfig.isCollectQueryStatsByNode();
|
||||
this.maxCallStack = GlobalProperties.getInt("ebean.maxCallStack", 5);
|
||||
this.maxCallStack = serverConfig.getMaxCallStack();
|
||||
|
||||
this.rollbackOnChecked = GlobalProperties.getBoolean("ebean.transaction.rollbackOnChecked", true);
|
||||
this.rollbackOnChecked = serverConfig.isTransactionRollbackOnChecked();
|
||||
this.transactionManager = config.getTransactionManager();
|
||||
this.transactionScopeManager = config.getTransactionScopeManager();
|
||||
|
||||
@@ -2081,9 +2038,7 @@ public final class DefaultServer implements SpiEbeanServer {
|
||||
|
||||
// create the 'interesting' part of the stackTrace
|
||||
StackTraceElement[] finalTrace = new StackTraceElement[stackLength];
|
||||
for (int i = 0; i < stackLength; i++) {
|
||||
finalTrace[i] = stackTrace[i + startIndex];
|
||||
}
|
||||
System.arraycopy(stackTrace, 0 + startIndex, finalTrace, 0, stackLength);
|
||||
|
||||
if (stackLength < 1) {
|
||||
// this should not really happen
|
||||
|
||||
@@ -2,10 +2,7 @@ package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
@@ -13,6 +10,7 @@ import javax.management.MBeanServerFactory;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -21,11 +19,6 @@ import com.avaje.ebean.cache.ServerCacheFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.cache.ServerCacheOptions;
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.DataSourceConfig;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.PstmtDelegate;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.UnderscoreNamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
@@ -38,7 +31,6 @@ import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourceAlert;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.SimpleDataSourceAlert;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* Default Server side implementation of ServerFactory.
|
||||
@@ -51,46 +43,18 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
private final JndiDataSourceLookup jndiDataSourceFactory;
|
||||
|
||||
private final BootupClassPathSearch bootupClassSearch;
|
||||
|
||||
private final AtomicInteger serverId = new AtomicInteger(1);
|
||||
|
||||
private final XmlConfigLoader xmlConfigLoader;
|
||||
public DefaultServerFactory(ContainerConfig containerConfig) {
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public DefaultServerFactory() {
|
||||
|
||||
this.clusterManager = new ClusterManager();
|
||||
this.clusterManager = new ClusterManager(containerConfig);
|
||||
this.jndiDataSourceFactory = new JndiDataSourceLookup();
|
||||
|
||||
List<String> packages = getSearchJarsPackages(GlobalProperties.get("ebean.search.packages", null));
|
||||
List<String> jars = getSearchJarsPackages(GlobalProperties.get("ebean.search.jars", null));
|
||||
|
||||
this.bootupClassSearch = new BootupClassPathSearch(null, packages, jars);
|
||||
this.xmlConfigLoader = new XmlConfigLoader(null);
|
||||
|
||||
this.xmlConfig = xmlConfigLoader.load();
|
||||
|
||||
// register so that we can shutdown any Ebean wide
|
||||
// resources such as clustering
|
||||
ShutdownManager.registerServerFactory(this);
|
||||
}
|
||||
|
||||
private List<String> getSearchJarsPackages(String searchPackages) {
|
||||
|
||||
List<String> hitList = new ArrayList<String>();
|
||||
|
||||
if (searchPackages != null) {
|
||||
|
||||
String[] entries = searchPackages.split("[ ,;]");
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
hitList.add(entries[i].trim());
|
||||
}
|
||||
}
|
||||
return hitList;
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
clusterManager.shutdown();
|
||||
}
|
||||
@@ -100,35 +64,26 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
*/
|
||||
public SpiEbeanServer createServer(String name) {
|
||||
|
||||
ConfigBuilder b = new ConfigBuilder();
|
||||
ServerConfig config = b.build(name);
|
||||
ServerConfig config = new ServerConfig();
|
||||
config.setName(name);
|
||||
|
||||
Properties prop = PropertyMap.defaultProperties();
|
||||
config.loadFromProperties(prop);
|
||||
|
||||
return createServer(config);
|
||||
}
|
||||
|
||||
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig, int uniqueServerId) {
|
||||
private SpiBackgroundExecutor createBackgroundExecutor(ServerConfig serverConfig) {
|
||||
|
||||
String namePrefix = "Ebean-" + serverConfig.getName();
|
||||
String namePrefix = "ebean-" + serverConfig.getName();
|
||||
|
||||
// the size of the pool for executing periodic tasks (such as cache flushing)
|
||||
int schedulePoolSize = GlobalProperties.getInt("backgroundExecutor.schedulePoolsize", 1);
|
||||
int schedulePoolSize = serverConfig.getBackgroundExecutorSchedulePoolSize();
|
||||
int corePoolSize = serverConfig.getBackgroundExecutorCorePoolSize();
|
||||
int maxPoolSize = serverConfig.getBackgroundExecutorMaxPoolSize();
|
||||
int idleSecs = serverConfig.getBackgroundExecutorIdleSecs();
|
||||
int shutdownSecs = serverConfig.getBackgroundExecutorShutdownSecs();
|
||||
|
||||
// the side of the main pool for immediate background task execution
|
||||
int minPoolSize = GlobalProperties.getInt("backgroundExecutor.minPoolSize", 0);
|
||||
int poolSize = GlobalProperties.getInt("backgroundExecutor.poolsize", 20);
|
||||
int maxPoolSize = GlobalProperties.getInt("backgroundExecutor.maxPoolSize", poolSize);
|
||||
|
||||
int idleSecs = GlobalProperties.getInt("backgroundExecutor.idlesecs", 120);
|
||||
int shutdownSecs = GlobalProperties.getInt("backgroundExecutor.shutdownSecs", 30);
|
||||
|
||||
boolean useTrad = GlobalProperties.getBoolean("backgroundExecutor.traditional", true);
|
||||
if (useTrad) {
|
||||
// this pool will use Idle seconds to maintain the thread count between min and max
|
||||
ThreadPool pool = new ThreadPool(namePrefix, true, null, minPoolSize, maxPoolSize, idleSecs*1000);
|
||||
return new TraditionalBackgroundExecutor(pool, schedulePoolSize, shutdownSecs, namePrefix);
|
||||
} else {
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
|
||||
}
|
||||
return new DefaultBackgroundExecutor(schedulePoolSize, corePoolSize, maxPoolSize, idleSecs, shutdownSecs, namePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,8 +118,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
pstmtDelegate = getOraclePstmtDelegate(serverConfig.getDataSource());
|
||||
}
|
||||
if (pstmtDelegate != null) {
|
||||
// We can support JDBC batching with Oracle
|
||||
// via OraclePreparedStatement
|
||||
// We can support JDBC batching with Oracle via OraclePreparedStatement
|
||||
pstmtBatch = new OraclePstmtBatch(pstmtDelegate);
|
||||
}
|
||||
if (pstmtBatch == null) {
|
||||
@@ -180,27 +134,30 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
ServerCacheManager cacheManager = getCacheManager(serverConfig);
|
||||
|
||||
int uniqueServerId = serverId.incrementAndGet();
|
||||
SpiBackgroundExecutor bgExecutor = createBackgroundExecutor(serverConfig, uniqueServerId);
|
||||
SpiBackgroundExecutor bgExecutor = createBackgroundExecutor(serverConfig);
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, bgExecutor, serverConfig, bootupClasses,
|
||||
pstmtBatch);
|
||||
XmlConfigLoader xmlConfigLoader = new XmlConfigLoader(null);
|
||||
XmlConfig xmlConfig = xmlConfigLoader.load();
|
||||
|
||||
InternalConfiguration c = new InternalConfiguration(xmlConfig, clusterManager, cacheManager, bgExecutor, serverConfig, bootupClasses, pstmtBatch);
|
||||
|
||||
DefaultServer server = new DefaultServer(c, cacheManager);
|
||||
|
||||
cacheManager.init(server);
|
||||
|
||||
MBeanServer mbeanServer;
|
||||
ArrayList<?> list = MBeanServerFactory.findMBeanServer(null);
|
||||
if (list.size() == 0) {
|
||||
// probably not running in a server
|
||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||
} else {
|
||||
// use the first MBeanServer
|
||||
mbeanServer = (MBeanServer) list.get(0);
|
||||
if (serverConfig.isRegisterJmxMBeans()) {
|
||||
MBeanServer mbeanServer;
|
||||
ArrayList<?> list = MBeanServerFactory.findMBeanServer(null);
|
||||
if (list.size() == 0) {
|
||||
// probably not running in a server
|
||||
mbeanServer = MBeanServerFactory.createMBeanServer();
|
||||
} else {
|
||||
// use the first MBeanServer
|
||||
mbeanServer = (MBeanServer) list.get(0);
|
||||
}
|
||||
server.registerMBeans(mbeanServer, uniqueServerId);
|
||||
}
|
||||
|
||||
server.registerMBeans(mbeanServer, uniqueServerId);
|
||||
|
||||
// generate and run DDL if required
|
||||
// if there are any other tasks requiring action in their plugins, do them as well
|
||||
server.executePlugins(online);
|
||||
@@ -215,9 +172,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
}
|
||||
|
||||
// warm the cache in 30 seconds
|
||||
int delaySecs = GlobalProperties.getInt("ebean.cacheWarmingDelay", 30);
|
||||
long sleepMillis = 1000 * delaySecs;
|
||||
|
||||
long sleepMillis = 1000 * serverConfig.getCacheWarmingDelay();
|
||||
if (sleepMillis > 0) {
|
||||
Timer t = new Timer("EbeanCacheWarmer", true);
|
||||
t.schedule(new CacheWarmer(server), sleepMillis);
|
||||
@@ -252,19 +207,15 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
// reasonable default settings are for a cache per bean type
|
||||
ServerCacheOptions beanOptions = new ServerCacheOptions();
|
||||
beanOptions.setMaxSize(GlobalProperties.getInt("cache.maxSize", 1000));
|
||||
// maxIdleTime 10 minutes
|
||||
beanOptions.setMaxIdleSecs(GlobalProperties.getInt("cache.maxIdleTime", 60 * 10));
|
||||
// maxTimeToLive 6 hrs
|
||||
beanOptions.setMaxSecsToLive(GlobalProperties.getInt("cache.maxTimeToLive", 60 * 60 * 6));
|
||||
beanOptions.setMaxSize(serverConfig.getCacheMaxSize());
|
||||
beanOptions.setMaxIdleSecs(serverConfig.getCacheMaxIdleTime());
|
||||
beanOptions.setMaxSecsToLive(serverConfig.getCacheMaxTimeToLive());
|
||||
|
||||
// reasonable default settings for the query cache per bean type
|
||||
ServerCacheOptions queryOptions = new ServerCacheOptions();
|
||||
queryOptions.setMaxSize(GlobalProperties.getInt("querycache.maxSize", 100));
|
||||
// maxIdleTime 10 minutes
|
||||
queryOptions.setMaxIdleSecs(GlobalProperties.getInt("querycache.maxIdleTime", 60 * 10));
|
||||
// maxTimeToLive 6 hours
|
||||
queryOptions.setMaxSecsToLive(GlobalProperties.getInt("querycache.maxTimeToLive", 60 * 60 * 6));
|
||||
queryOptions.setMaxSize(serverConfig.getQueryCacheMaxSize());
|
||||
queryOptions.setMaxIdleSecs(serverConfig.getQueryCacheMaxIdleTime());
|
||||
queryOptions.setMaxSecsToLive(serverConfig.getQueryCacheMaxTimeToLive());
|
||||
|
||||
ServerCacheFactory cacheFactory = serverConfig.getServerCacheFactory();
|
||||
if (cacheFactory == null) {
|
||||
@@ -303,17 +254,8 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
return new BootupClasses(serverConfig.getClasses());
|
||||
}
|
||||
|
||||
List<String> jars = serverConfig.getJars();
|
||||
List<String> packages = serverConfig.getPackages();
|
||||
|
||||
if ((packages != null && !packages.isEmpty()) || (jars != null && !jars.isEmpty())) {
|
||||
// filter by package name
|
||||
BootupClassPathSearch search = new BootupClassPathSearch(null, packages, jars);
|
||||
return search.getBootupClasses();
|
||||
}
|
||||
|
||||
// just use classes we can find via class path search
|
||||
return bootupClassSearch.getBootupClasses().createCopy();
|
||||
BootupClassPathSearch search = new BootupClassPathSearch(null, serverConfig.getPackages(), serverConfig.getJars(), serverConfig.getClassPathReaderClassName());
|
||||
return search.getBootupClasses();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -323,22 +265,6 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
if (config.getNamingConvention() == null) {
|
||||
UnderscoreNamingConvention nc = new UnderscoreNamingConvention();
|
||||
config.setNamingConvention(nc);
|
||||
|
||||
String v = config.getProperty("namingConvention.useForeignKeyPrefix");
|
||||
if (v != null) {
|
||||
boolean useForeignKeyPrefix = Boolean.valueOf(v);
|
||||
nc.setUseForeignKeyPrefix(useForeignKeyPrefix);
|
||||
}
|
||||
|
||||
String sequenceFormat = config.getProperty("namingConvention.sequenceFormat");
|
||||
if (sequenceFormat != null) {
|
||||
nc.setSequenceFormat(sequenceFormat);
|
||||
}
|
||||
|
||||
String schema = config.getProperty("namingConvention.schema");
|
||||
if (schema != null) {
|
||||
nc.setSchema(schema);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,7 +277,6 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
if (dbPlatform == null) {
|
||||
|
||||
DatabasePlatformFactory factory = new DatabasePlatformFactory();
|
||||
|
||||
DatabasePlatform db = factory.create(config);
|
||||
config.setDatabasePlatform(db);
|
||||
logger.info("DatabasePlatform name:" + config.getName() + " platform:" + db.getName());
|
||||
@@ -370,7 +295,7 @@ public class DefaultServerFactory implements BootupEbeanManager {
|
||||
|
||||
private DataSource getDataSourceFromConfig(ServerConfig config) {
|
||||
|
||||
DataSource ds = null;
|
||||
DataSource ds;
|
||||
|
||||
if (config.getDataSourceJndiName() != null) {
|
||||
ds = jndiDataSourceFactory.lookup(config.getDataSourceJndiName());
|
||||
|
||||
@@ -1,266 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.ExpressionFactory;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.ExternalTransactionManager;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.text.json.JsonContext;
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManager;
|
||||
import com.avaje.ebeaninternal.server.autofetch.AutoFetchManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.deploy.DeployOrmXml;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.expression.DefaultExpressionFactory;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.persist.DefaultPersister;
|
||||
import com.avaje.ebeaninternal.server.query.CQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultOrmQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.query.DefaultRelationalQueryEngine;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManager;
|
||||
import com.avaje.ebeaninternal.server.resource.ResourceManagerFactory;
|
||||
import com.avaje.ebeaninternal.server.text.json.DJsonContext;
|
||||
<<<<<<< HEAD
|
||||
import com.avaje.ebeaninternal.server.text.json.DefaultJsonValueAdapter;
|
||||
import com.avaje.ebeaninternal.server.transaction.AutoCommitTransactionManager;
|
||||
=======
|
||||
>>>>>>> json-refactor
|
||||
import com.avaje.ebeaninternal.server.transaction.DefaultTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.ExternalTransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.JtaTransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionScopeManager;
|
||||
import com.avaje.ebeaninternal.server.type.DefaultTypeManager;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
|
||||
/**
|
||||
* Used to extend the ServerConfig with additional objects used to configure and
|
||||
* construct an EbeanServer.
|
||||
*/
|
||||
public class InternalConfiguration {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InternalConfiguration.class);
|
||||
|
||||
private final ServerConfig serverConfig;
|
||||
|
||||
private final BootupClasses bootupClasses;
|
||||
|
||||
private final DeployInherit deployInherit;
|
||||
|
||||
private final ResourceManager resourceManager;
|
||||
|
||||
private final DeployOrmXml deployOrmXml;
|
||||
|
||||
private final TypeManager typeManager;
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
private final DeployCreateProperties deployCreateProperties;
|
||||
|
||||
private final DeployUtil deployUtil;
|
||||
|
||||
private final BeanDescriptorManager beanDescriptorManager;
|
||||
|
||||
private final TransactionManager transactionManager;
|
||||
|
||||
private final TransactionScopeManager transactionScopeManager;
|
||||
|
||||
private final CQueryEngine cQueryEngine;
|
||||
|
||||
private final ClusterManager clusterManager;
|
||||
|
||||
private final ServerCacheManager cacheManager;
|
||||
|
||||
private final ExpressionFactory expressionFactory;
|
||||
|
||||
private final SpiBackgroundExecutor backgroundExecutor;
|
||||
|
||||
private final PstmtBatch pstmtBatch;
|
||||
|
||||
private final XmlConfig xmlConfig;
|
||||
|
||||
public InternalConfiguration(XmlConfig xmlConfig, ClusterManager clusterManager,
|
||||
ServerCacheManager cacheManager, SpiBackgroundExecutor backgroundExecutor,
|
||||
ServerConfig serverConfig, BootupClasses bootupClasses, PstmtBatch pstmtBatch) {
|
||||
|
||||
this.xmlConfig = xmlConfig;
|
||||
this.pstmtBatch = pstmtBatch;
|
||||
this.clusterManager = clusterManager;
|
||||
this.backgroundExecutor = backgroundExecutor;
|
||||
this.cacheManager = cacheManager;
|
||||
this.serverConfig = serverConfig;
|
||||
this.bootupClasses = bootupClasses;
|
||||
this.expressionFactory = new DefaultExpressionFactory();
|
||||
|
||||
this.typeManager = new DefaultTypeManager(serverConfig, bootupClasses);
|
||||
this.binder = new Binder(typeManager);
|
||||
|
||||
this.resourceManager = ResourceManagerFactory.createResourceManager(serverConfig);
|
||||
this.deployOrmXml = new DeployOrmXml(resourceManager.getResourceSource());
|
||||
this.deployInherit = new DeployInherit(bootupClasses);
|
||||
|
||||
this.deployCreateProperties = new DeployCreateProperties(typeManager);
|
||||
this.deployUtil = new DeployUtil(typeManager, serverConfig);
|
||||
|
||||
this.beanDescriptorManager = new BeanDescriptorManager(this);
|
||||
beanDescriptorManager.deploy();
|
||||
|
||||
this.transactionManager = createTransactionManager();
|
||||
|
||||
this.cQueryEngine = new CQueryEngine(serverConfig.getDatabasePlatform(), binder);
|
||||
|
||||
ExternalTransactionManager externalTransactionManager = serverConfig.getExternalTransactionManager();
|
||||
if (externalTransactionManager == null && serverConfig.isUseJtaTransactionManager()) {
|
||||
externalTransactionManager = new JtaTransactionManager();
|
||||
}
|
||||
if (externalTransactionManager != null) {
|
||||
externalTransactionManager.setTransactionManager(transactionManager);
|
||||
this.transactionScopeManager = new ExternalTransactionScopeManager(transactionManager, externalTransactionManager);
|
||||
logger.info("Using Transaction Manager [" + externalTransactionManager.getClass() + "]");
|
||||
} else {
|
||||
this.transactionScopeManager = new DefaultTransactionScopeManager(transactionManager);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the TransactionManager taking into account autoCommit mode.
|
||||
*/
|
||||
private TransactionManager createTransactionManager() {
|
||||
|
||||
if (isAutoCommitMode()) {
|
||||
return new AutoCommitTransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
return new TransactionManager(clusterManager, backgroundExecutor, serverConfig, beanDescriptorManager, this.getBootupClasses());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if autoCommit mode is on.
|
||||
*/
|
||||
private boolean isAutoCommitMode() {
|
||||
if (serverConfig.isAutoCommitMode()) {
|
||||
// explicitly set
|
||||
return true;
|
||||
}
|
||||
DataSource dataSource = serverConfig.getDataSource();
|
||||
if (dataSource instanceof DataSourcePool && ((DataSourcePool)dataSource).getAutoCommit()) {
|
||||
// We know the DataSourcePool is using autoCommit
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public JsonContext createJsonContext(SpiEbeanServer server) {
|
||||
|
||||
return new DJsonContext(server);
|
||||
}
|
||||
|
||||
public XmlConfig getXmlConfig() {
|
||||
return xmlConfig;
|
||||
}
|
||||
|
||||
public AutoFetchManager createAutoFetchManager(SpiEbeanServer server) {
|
||||
return AutoFetchManagerFactory.create(server, serverConfig, resourceManager);
|
||||
}
|
||||
|
||||
public RelationalQueryEngine createRelationalQueryEngine() {
|
||||
return new DefaultRelationalQueryEngine(binder, serverConfig.getDatabaseBooleanTrue());
|
||||
}
|
||||
|
||||
public OrmQueryEngine createOrmQueryEngine() {
|
||||
return new DefaultOrmQueryEngine(beanDescriptorManager, cQueryEngine);
|
||||
}
|
||||
|
||||
public Persister createPersister(SpiEbeanServer server) {
|
||||
return new DefaultPersister(server, binder, beanDescriptorManager, pstmtBatch);
|
||||
}
|
||||
|
||||
public PstmtBatch getPstmtBatch() {
|
||||
return pstmtBatch;
|
||||
}
|
||||
|
||||
public ServerCacheManager getCacheManager() {
|
||||
return cacheManager;
|
||||
}
|
||||
|
||||
public BootupClasses getBootupClasses() {
|
||||
return bootupClasses;
|
||||
}
|
||||
|
||||
public DatabasePlatform getDatabasePlatform() {
|
||||
return serverConfig.getDatabasePlatform();
|
||||
}
|
||||
|
||||
public ServerConfig getServerConfig() {
|
||||
return serverConfig;
|
||||
}
|
||||
|
||||
public ExpressionFactory getExpressionFactory() {
|
||||
return expressionFactory;
|
||||
}
|
||||
|
||||
public TypeManager getTypeManager() {
|
||||
return typeManager;
|
||||
}
|
||||
|
||||
public Binder getBinder() {
|
||||
return binder;
|
||||
}
|
||||
|
||||
public BeanDescriptorManager getBeanDescriptorManager() {
|
||||
return beanDescriptorManager;
|
||||
}
|
||||
|
||||
public DeployInherit getDeployInherit() {
|
||||
return deployInherit;
|
||||
}
|
||||
|
||||
public ResourceManager getResourceManager() {
|
||||
return resourceManager;
|
||||
}
|
||||
|
||||
public DeployOrmXml getDeployOrmXml() {
|
||||
return deployOrmXml;
|
||||
}
|
||||
|
||||
public DeployCreateProperties getDeployCreateProperties() {
|
||||
return deployCreateProperties;
|
||||
}
|
||||
|
||||
public DeployUtil getDeployUtil() {
|
||||
return deployUtil;
|
||||
}
|
||||
|
||||
public TransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
public TransactionScopeManager getTransactionScopeManager() {
|
||||
return transactionScopeManager;
|
||||
}
|
||||
|
||||
public CQueryEngine getCQueryEngine() {
|
||||
return cQueryEngine;
|
||||
}
|
||||
|
||||
public ClusterManager getClusterManager() {
|
||||
return clusterManager;
|
||||
}
|
||||
|
||||
public SpiBackgroundExecutor getBackgroundExecutor() {
|
||||
return backgroundExecutor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,9 +6,6 @@ import javax.naming.NamingException;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to lookup a DataSource from JNDI.
|
||||
*/
|
||||
@@ -16,8 +13,6 @@ public class JndiDataSourceLookup {
|
||||
|
||||
private static final String DEFAULT_PREFIX = "java:comp/env/jdbc/";
|
||||
|
||||
String jndiPrefix = GlobalProperties.get("ebean.datasource.jndi.prefix", DEFAULT_PREFIX);
|
||||
|
||||
public JndiDataSourceLookup() {
|
||||
}
|
||||
|
||||
@@ -32,7 +27,7 @@ public class JndiDataSourceLookup {
|
||||
try {
|
||||
|
||||
if (!jndiName.startsWith("java:")){
|
||||
jndiName = jndiPrefix + jndiName;
|
||||
jndiName = DEFAULT_PREFIX + jndiName;
|
||||
}
|
||||
|
||||
Context ctx = new InitialContext();
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.lib.ShutdownManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.servlet.ServletContextEvent;
|
||||
|
||||
/**
|
||||
* Listens for webserver server starting and stopping events.
|
||||
@@ -19,8 +14,6 @@ import org.slf4j.LoggerFactory;
|
||||
*/
|
||||
public class ServletContextListener implements javax.servlet.ServletContextListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ServletContextListener.class);
|
||||
|
||||
/**
|
||||
* The servlet container is stopping.
|
||||
*/
|
||||
@@ -29,29 +22,10 @@ public class ServletContextListener implements javax.servlet.ServletContextListe
|
||||
}
|
||||
|
||||
/**
|
||||
* The servlet container is starting.
|
||||
* <p>
|
||||
* Initialise the properties file using SystemProperties.initWebapp();
|
||||
* and start Ebean.
|
||||
* </p>
|
||||
* Do nothing on startup.
|
||||
*/
|
||||
public void contextInitialized(ServletContextEvent event) {
|
||||
|
||||
try {
|
||||
ServletContext servletContext = event.getServletContext();
|
||||
GlobalProperties.setServletContext(servletContext);
|
||||
|
||||
if (servletContext != null) {
|
||||
String servletRealPath = servletContext.getRealPath("");
|
||||
GlobalProperties.put("servlet.realpath", servletRealPath);
|
||||
logger.info("servlet.realpath=[" + servletRealPath + "]");
|
||||
}
|
||||
|
||||
Ebean.getServer(null);
|
||||
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.core;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
|
||||
import com.avaje.ebeaninternal.server.lib.DaemonScheduleThreadPool;
|
||||
import com.avaje.ebeaninternal.server.lib.thread.ThreadPool;
|
||||
|
||||
/**
|
||||
* BackgroundExecutor using my traditional ThreadPool that will grow and trim.
|
||||
*
|
||||
* @author rbygrave
|
||||
*/
|
||||
public class TraditionalBackgroundExecutor implements SpiBackgroundExecutor {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(TraditionalBackgroundExecutor.class);
|
||||
|
||||
private final ThreadPool pool;
|
||||
|
||||
private final DaemonScheduleThreadPool schedulePool;
|
||||
|
||||
/**
|
||||
* Construct the default implementation of BackgroundExecutor.
|
||||
*/
|
||||
public TraditionalBackgroundExecutor(ThreadPool pool, int schedulePoolSize, int shutdownWaitSeconds, String namePrefix) {
|
||||
this.pool = pool;
|
||||
this.schedulePool = new DaemonScheduleThreadPool(schedulePoolSize, shutdownWaitSeconds, namePrefix+"-periodic-");
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a Runnable using a background thread.
|
||||
*/
|
||||
public void execute(Runnable r) {
|
||||
pool.assign(r, true);
|
||||
}
|
||||
|
||||
public void executePeriodically(Runnable r, long delay, TimeUnit unit) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Registering for executePeriodically {} delay:{} {}",r, delay, unit);
|
||||
}
|
||||
schedulePool.scheduleWithFixedDelay(r, delay, delay, unit);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Shutting down");
|
||||
}
|
||||
pool.shutdown();
|
||||
schedulePool.shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,25 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.Model;
|
||||
import com.avaje.ebean.RawSql;
|
||||
@@ -29,7 +9,6 @@ import com.avaje.ebean.bean.EntityBean;
|
||||
import com.avaje.ebean.cache.ServerCacheManager;
|
||||
import com.avaje.ebean.config.EncryptKey;
|
||||
import com.avaje.ebean.config.EncryptKeyManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.NamingConvention;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.DbIdentity;
|
||||
@@ -38,35 +17,31 @@ import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebean.event.BeanFinder;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.core.InternalConfiguration;
|
||||
import com.avaje.ebeaninternal.server.core.Message;
|
||||
import com.avaje.ebeaninternal.server.core.XmlConfig;
|
||||
import com.avaje.ebeaninternal.server.core.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor.EntityType;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinderEmbedded;
|
||||
import com.avaje.ebeaninternal.server.deploy.id.IdBinderFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanDescriptor;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocMany;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployBeanInfo;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployCreateProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployInherit;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.DeployUtil;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.ReadAnnotations;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.TransientProperties;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.parse.*;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.Dnode;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfo;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertyInfoFactory;
|
||||
import com.avaje.ebeaninternal.server.properties.BeanPropertiesReader;
|
||||
import com.avaje.ebeaninternal.server.properties.EnhanceBeanPropertyInfoFactory;
|
||||
import com.avaje.ebeaninternal.server.type.TypeManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.persistence.Transient;
|
||||
import javax.sql.DataSource;
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Creates BeanDescriptors.
|
||||
@@ -153,6 +128,8 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
private final BeanLifecycleAdapterFactory beanLifecycleAdapterFactory;
|
||||
|
||||
private final boolean eagerFetchLobs;
|
||||
|
||||
/**
|
||||
* Create for a given database dbConfig.
|
||||
*/
|
||||
@@ -167,6 +144,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
this.encryptKeyManager = config.getServerConfig().getEncryptKeyManager();
|
||||
this.databasePlatform = config.getServerConfig().getDatabasePlatform();
|
||||
this.idBinderFactory = new IdBinderFactory(databasePlatform.isIdInExpandedForm());
|
||||
this.eagerFetchLobs = config.getServerConfig().isEagerFetchLobs();
|
||||
|
||||
this.bootupClasses = config.getBootupClasses();
|
||||
this.createProperties = config.getDeployCreateProperties();
|
||||
@@ -397,12 +375,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
String msg = "SERIOUS ERROR: The hashCode() and equals() methods *MUST* be implemented ";
|
||||
msg += "on Embedded bean " + idType + " as it is used as an Id for " + beanType;
|
||||
|
||||
if (GlobalProperties.getBoolean("ebean.strict", true)) {
|
||||
throw new PersistenceException(msg, source);
|
||||
} else {
|
||||
logger.error(msg, source);
|
||||
}
|
||||
throw new PersistenceException(msg, source);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1017,7 +990,7 @@ public class BeanDescriptorManager implements BeanDescriptorMap {
|
||||
|
||||
DeployBeanInfo<T> info = new DeployBeanInfo<T>(deployUtil, desc);
|
||||
|
||||
readAnnotations.readInitial(info);
|
||||
readAnnotations.readInitial(info, eagerFetchLobs);
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.deploy;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.core.InternString;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanTable;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployTableJoin;
|
||||
@@ -99,15 +98,11 @@ public class BeanTable {
|
||||
}
|
||||
|
||||
if (complexKey){
|
||||
// check to see if we want prefixes by default with complex keys
|
||||
boolean usePrefixOnComplex = GlobalProperties.getBoolean("ebean.prefixComplexKeys", false);
|
||||
if (!usePrefixOnComplex){
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
String msg = "On table["+baseTable+"] foreign key column ["+lc+"]";
|
||||
logger.debug(msg);
|
||||
fk = lc;
|
||||
}
|
||||
// just to copy the column name rather than prefix with the foreignKeyPrefix.
|
||||
// I think that with complex keys this is the more common approach.
|
||||
String msg = "On table["+baseTable+"] foreign key column ["+lc+"]";
|
||||
logger.debug(msg);
|
||||
fk = lc;
|
||||
}
|
||||
|
||||
DeployTableJoinColumn joinCol = new DeployTableJoinColumn(lc, fk);
|
||||
|
||||
@@ -1,21 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.deploy.parse;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
import com.avaje.ebean.annotation.*;
|
||||
import com.avaje.ebean.config.EncryptDeploy;
|
||||
import com.avaje.ebean.config.EncryptDeploy.Mode;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncrypt;
|
||||
import com.avaje.ebean.config.dbplatform.DbEncryptFunction;
|
||||
import com.avaje.ebean.config.dbplatform.IdType;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.generatedproperty.GeneratedPropertyFactory;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssoc;
|
||||
@@ -23,12 +13,14 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyAssocOne;
|
||||
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanPropertyCompound;
|
||||
import com.avaje.ebeaninternal.server.idgen.UuidIdGenerator;
|
||||
import com.avaje.ebeaninternal.server.lib.util.StringHelper;
|
||||
import com.avaje.ebeaninternal.server.type.CtCompoundType;
|
||||
import com.avaje.ebeaninternal.server.type.DataEncryptSupport;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarType;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBytesBase;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeBytesEncrypted;
|
||||
import com.avaje.ebeaninternal.server.type.ScalarTypeEncryptedWrapper;
|
||||
import com.avaje.ebeaninternal.server.type.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
import java.sql.Types;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Read the field level deployment annotations.
|
||||
@@ -42,10 +34,10 @@ public class AnnotationFields extends AnnotationParser {
|
||||
|
||||
private GeneratedPropertyFactory generatedPropFactory = new GeneratedPropertyFactory();
|
||||
|
||||
public AnnotationFields(DeployBeanInfo<?> info) {
|
||||
public AnnotationFields(DeployBeanInfo<?> info, boolean eagerFetchLobs) {
|
||||
super(info);
|
||||
|
||||
if (GlobalProperties.getBoolean("ebean.lobEagerFetch", false)) {
|
||||
if (eagerFetchLobs) {
|
||||
defaultLobFetchType = FetchType.EAGER;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,11 +15,11 @@ public class ReadAnnotations {
|
||||
* to resolve the relationships etc.
|
||||
* </p>
|
||||
*/
|
||||
public void readInitial(DeployBeanInfo<?> info){
|
||||
public void readInitial(DeployBeanInfo<?> info, boolean eagerFetchLobs){
|
||||
|
||||
try {
|
||||
new AnnotationClass(info).parse();
|
||||
new AnnotationFields(info).parse();
|
||||
new AnnotationFields(info, eagerFetchLobs).parse();
|
||||
|
||||
} catch (RuntimeException e){
|
||||
String msg = "Error reading annotations for "+info;
|
||||
|
||||
@@ -6,18 +6,15 @@ import com.avaje.ebean.config.PstmtDelegate;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.ExtendedPreparedStatement;
|
||||
|
||||
/**
|
||||
* Implementation of PstmtDelegate from Ebean's own
|
||||
* DataSource.
|
||||
*
|
||||
* @author rbygrave
|
||||
* Implementation of PstmtDelegate from Ebean's own DataSource.
|
||||
*/
|
||||
public class StandardPstmtDelegate implements PstmtDelegate {
|
||||
|
||||
/**
|
||||
* Unwrap the PreparedStatement from Ebean's DataSource implementation.
|
||||
*/
|
||||
public PreparedStatement unwrap(PreparedStatement pstmt) {
|
||||
|
||||
return ((ExtendedPreparedStatement)pstmt).getDelegate();
|
||||
}
|
||||
/**
|
||||
* Unwrap the PreparedStatement from Ebean's DataSource implementation.
|
||||
*/
|
||||
public PreparedStatement unwrap(PreparedStatement pstmt) {
|
||||
|
||||
return ((ExtendedPreparedStatement) pstmt).getDelegate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ public final class DaemonThreadPool extends ThreadPoolExecutor {
|
||||
* the time in seconds allowed for the pool to shutdown nicely. After
|
||||
* this the pool is forced to shutdown.
|
||||
*/
|
||||
public DaemonThreadPool(int coreSize, long keepAliveSecs, int shutdownWaitSeconds, String namePrefix) {
|
||||
public DaemonThreadPool(int coreSize, int maximumPoolSize, long keepAliveSecs, int shutdownWaitSeconds, String namePrefix) {
|
||||
|
||||
super(coreSize, coreSize, keepAliveSecs, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory(namePrefix));
|
||||
super(coreSize, maximumPoolSize, keepAliveSecs, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new DaemonThreadFactory(namePrefix));
|
||||
allowCoreThreadTimeOut(true);
|
||||
this.shutdownWaitSeconds = shutdownWaitSeconds;
|
||||
this.namePrefix = namePrefix;
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.lib;
|
||||
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Driver;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
@@ -7,14 +13,6 @@ import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.common.BootupEbeanManager;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
|
||||
/**
|
||||
* Manages the shutdown of the JVM Runtime.
|
||||
* <p>
|
||||
@@ -33,12 +31,9 @@ public final class ShutdownManager {
|
||||
|
||||
static BootupEbeanManager serverFactory;
|
||||
|
||||
static boolean whyShutdown;
|
||||
|
||||
static {
|
||||
// Register the Shutdown hook
|
||||
registerShutdownHook();
|
||||
whyShutdown = GlobalProperties.getBoolean("debug.shutdown.why",false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,19 +113,11 @@ public final class ShutdownManager {
|
||||
logger.debug("Shutting down");
|
||||
}
|
||||
|
||||
if (whyShutdown) {
|
||||
try {
|
||||
throw new RuntimeException("debug.shutdown.why=true ...");
|
||||
} catch (Throwable e) {
|
||||
logger.warn("Stacktrace showing why shutdown was fired", e);
|
||||
}
|
||||
}
|
||||
|
||||
stopping = true;
|
||||
|
||||
deregisterShutdownHook();
|
||||
|
||||
String shutdownRunner = GlobalProperties.get("system.shutdown.runnable", null);
|
||||
String shutdownRunner = System.getProperty("ebean.shutdown.runnable");
|
||||
if (shutdownRunner != null) {
|
||||
try {
|
||||
// A custom runnable executed at the start of shutdown
|
||||
@@ -157,7 +144,7 @@ public final class ShutdownManager {
|
||||
}
|
||||
}
|
||||
|
||||
if (GlobalProperties.getBoolean("datasource.deregisterAllDrivers", false)) {
|
||||
if ("true".equalsIgnoreCase(System.getProperty("ebean.datasource.deregisterAllDrivers", "false"))) {
|
||||
deregisterAllJdbcDrivers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
package com.avaje.ebeaninternal.server.lib.sql;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailEvent;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailListener;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailMessage;
|
||||
import com.avaje.ebeaninternal.server.lib.util.MailSender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A simple smtp email alert that sends a email message on dataSourceDown and
|
||||
@@ -23,7 +21,11 @@ public class SimpleDataSourceAlert implements DataSourceAlert, MailListener {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(SimpleDataSourceAlert.class);
|
||||
|
||||
// boolean sendInBackGround = true;
|
||||
private static String alertMailServerName = System.getProperty("ebean.datasource.alert.mailserver");
|
||||
|
||||
private static String fromUser = System.getProperty("ebean.datasource.alert.fromUser");
|
||||
private static String fromEmail = System.getProperty("ebean.datasource.alert.fromEmail");
|
||||
private static String toEmail = System.getProperty("ebean.datasource.alert.toEmail");
|
||||
|
||||
/**
|
||||
* Create a SimpleAlerter.
|
||||
@@ -79,15 +81,10 @@ public class SimpleDataSourceAlert implements DataSourceAlert, MailListener {
|
||||
|
||||
private void sendMessage(String subject, String msg) {
|
||||
|
||||
String mailServerName = GlobalProperties.get("datasource.alert.mailserver", null);
|
||||
if (mailServerName == null) {
|
||||
if (alertMailServerName == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String fromUser = GlobalProperties.get("datasource.alert.fromuser", null);
|
||||
String fromEmail = GlobalProperties.get("datasource.alert.fromemail", null);
|
||||
String toEmail = GlobalProperties.get("datasource.alert.toemail", null);
|
||||
|
||||
MailMessage data = new MailMessage();
|
||||
data.setSender(fromUser, fromEmail);
|
||||
data.addBodyLine(msg);
|
||||
@@ -95,15 +92,15 @@ public class SimpleDataSourceAlert implements DataSourceAlert, MailListener {
|
||||
|
||||
String[] toList = toEmail.split(",");
|
||||
if (toList.length == 0) {
|
||||
throw new RuntimeException("alert.toemail has not been set?");
|
||||
logger.error("alert.toemail has not been set?");
|
||||
} else {
|
||||
for (int i = 0; i < toList.length; i++) {
|
||||
data.addRecipient(null, toList[i].trim());
|
||||
}
|
||||
MailSender sender = new MailSender(alertMailServerName);
|
||||
sender.setMailListener(this);
|
||||
sender.sendInBackground(data);
|
||||
}
|
||||
for (int i = 0; i < toList.length; i++) {
|
||||
data.addRecipient(null, toList[i].trim());
|
||||
}
|
||||
|
||||
MailSender sender = new MailSender(mailServerName);
|
||||
sender.setMailListener(this);
|
||||
sender.sendInBackground(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,278 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.lib.thread;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A thread that belongs to a ThreadPool. It will return to the Threadpool when
|
||||
* it has finished its assigned task.
|
||||
*/
|
||||
public class PooledThread implements Runnable {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PooledThread.class);
|
||||
|
||||
/**
|
||||
* Flag to indicate that the thread was interrupted.
|
||||
*/
|
||||
private boolean wasInterrupted;
|
||||
|
||||
/**
|
||||
* The time the thread was last used.
|
||||
*/
|
||||
private long lastUsedTime;
|
||||
|
||||
/**
|
||||
* The work to run
|
||||
*/
|
||||
private Work work;
|
||||
|
||||
/**
|
||||
* Set to indicate the thread is stopping.
|
||||
*/
|
||||
private boolean isStopping;
|
||||
|
||||
/**
|
||||
* Set when the thread has stopped.
|
||||
*/
|
||||
private boolean isStopped;
|
||||
/**
|
||||
* The background thread.
|
||||
*/
|
||||
private Thread thread;
|
||||
|
||||
/**
|
||||
* The pool this worker belongs to.
|
||||
*/
|
||||
private ThreadPool threadPool;
|
||||
|
||||
/**
|
||||
* The name of the Thread
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* The thread synchronization object.
|
||||
*/
|
||||
private Object threadMonitor = new Object();
|
||||
|
||||
/**
|
||||
* The monitor for work notification.
|
||||
*/
|
||||
private Object workMonitor = new Object();
|
||||
|
||||
/**
|
||||
* Total number of work performed.
|
||||
*/
|
||||
private int totalWorkCount;
|
||||
|
||||
/**
|
||||
* Total work execution time.
|
||||
*/
|
||||
private long totalWorkExecutionTime;
|
||||
|
||||
/**
|
||||
* Create the PooledThread.
|
||||
*/
|
||||
protected PooledThread(ThreadPool threadPool, String name, boolean isDaemon, Integer threadPriority) {
|
||||
|
||||
this.name = name;
|
||||
this.threadPool = threadPool;
|
||||
this.lastUsedTime = System.currentTimeMillis();
|
||||
|
||||
thread = new Thread(this, name);
|
||||
thread.setDaemon(isDaemon);
|
||||
|
||||
if (threadPriority != null) {
|
||||
thread.setPriority(threadPriority.intValue());
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name;
|
||||
}
|
||||
|
||||
protected void start() {
|
||||
thread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign work to this thread. The thread will notify the listener when it has
|
||||
* finished the work.
|
||||
*/
|
||||
public boolean assignWork(Work work) {
|
||||
synchronized (workMonitor) {
|
||||
this.work = work;
|
||||
workMonitor.notifyAll();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* process any assigned work until stopped or interrupted.
|
||||
*/
|
||||
public void run() {
|
||||
// process assigned work until we receive a shutdown signal
|
||||
synchronized (workMonitor) {
|
||||
while (!isStopping) {
|
||||
try {
|
||||
if (work == null) {
|
||||
workMonitor.wait();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
doTheWork();
|
||||
}
|
||||
}
|
||||
|
||||
// Tell stop() we have shut ourselves down successfully
|
||||
synchronized (threadMonitor) {
|
||||
threadMonitor.notifyAll();
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("PooledThread [" + getName() + "] finished ");
|
||||
}
|
||||
isStopped = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actually do the work and gather the appropriate measures.
|
||||
*/
|
||||
private void doTheWork() {
|
||||
if (isStopping) {
|
||||
return;
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
if (work == null) {
|
||||
// probably shutting down the thread
|
||||
|
||||
} else {
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("start work "+work);
|
||||
}
|
||||
|
||||
work.setStartTime(startTime);
|
||||
work.getRunnable().run();
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("finished work "+work);
|
||||
}
|
||||
|
||||
} catch (Throwable ex) {
|
||||
logger.error(null, ex);
|
||||
|
||||
if (wasInterrupted) {
|
||||
this.isStopping = true;
|
||||
threadPool.removeThread(this);
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("PooledThread [" + name + "] removed due to interrupt");
|
||||
}
|
||||
try {
|
||||
thread.interrupt();
|
||||
} catch (Exception e) {
|
||||
logger.error("Error interrupting PooledThead[" + name + "]", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastUsedTime = System.currentTimeMillis();
|
||||
totalWorkCount++;
|
||||
totalWorkExecutionTime = totalWorkExecutionTime + lastUsedTime - startTime;
|
||||
this.work = null;
|
||||
threadPool.returnThread(this);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to interrupt the thread.
|
||||
* <p>
|
||||
* If the Thread was interrupted then it will be removed from the pool.
|
||||
* </p>
|
||||
*/
|
||||
public void interrupt() {
|
||||
|
||||
// set a flag so doTheWork knows that it was interrupted
|
||||
// and removes rather than returns
|
||||
wasInterrupted = true;
|
||||
try {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("interrupt()");
|
||||
}
|
||||
thread.interrupt();
|
||||
|
||||
} catch (SecurityException ex) {
|
||||
wasInterrupted = false;
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the thread has finished.
|
||||
*/
|
||||
public boolean isStopped() {
|
||||
return isStopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the thread relatively nicely. It will wait a maximum of 10 seconds for
|
||||
* it to complete any existing work.
|
||||
*/
|
||||
protected void stop() {
|
||||
isStopping = true;
|
||||
|
||||
synchronized (threadMonitor) {
|
||||
|
||||
assignWork(null);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("stopping thread ["+name+"]");
|
||||
}
|
||||
try {
|
||||
threadMonitor.wait(10000);
|
||||
} catch (InterruptedException e) {
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread = null;
|
||||
threadPool.removeThread(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the name of the thread.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the currently executing work, otherwise null.
|
||||
*/
|
||||
public Work getWork() {
|
||||
return work;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total number of jobs this thread has run.
|
||||
*/
|
||||
public int getTotalWorkCount() {
|
||||
return totalWorkCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* The total time for performing all assigned work.
|
||||
*/
|
||||
public long getTotalWorkExecutionTime() {
|
||||
return totalWorkExecutionTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time this thread was last used.
|
||||
*/
|
||||
public long getLastUsedTime() {
|
||||
return lastUsedTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,502 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.lib.thread;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* This is a pool of threads which can be assigned work.
|
||||
* <p>
|
||||
* The Pool will automatically grow as required up to its maximum pool size. The
|
||||
* Pool will be automatically shrink by trimming threads that have been idle for
|
||||
* some time.
|
||||
* </p>
|
||||
*/
|
||||
public class ThreadPool {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ThreadPool.class);
|
||||
|
||||
/**
|
||||
* The max idle time used to trim idle threads from the pool.
|
||||
*/
|
||||
private long maxIdleTime;
|
||||
|
||||
/**
|
||||
* The name of the pool
|
||||
*/
|
||||
private String poolName;
|
||||
|
||||
/**
|
||||
* The initial pool size.
|
||||
*/
|
||||
private int minSize;
|
||||
|
||||
/**
|
||||
* Whether or not the threads are going to be Daemon threads.
|
||||
*/
|
||||
private boolean isDaemon;
|
||||
|
||||
/**
|
||||
* The priority or the threads. Can be null, in which case the threads have
|
||||
* the default priority.
|
||||
*/
|
||||
private Integer threadPriority;
|
||||
|
||||
/**
|
||||
* Incrementing int for thread name. NB: currentThreadCount will go up and
|
||||
* down as the pool grows and shrinks.
|
||||
*/
|
||||
private int uniqueThreadID;
|
||||
|
||||
/**
|
||||
* The maximum number of threads to grow to. Hitting this limit will have
|
||||
* performance ramifications.
|
||||
*/
|
||||
private int maxSize = 100;
|
||||
|
||||
/**
|
||||
* Flag that the pool should terminate all the threads and stop.
|
||||
*/
|
||||
private boolean stopThePool;
|
||||
|
||||
/**
|
||||
* Flag to indicate that the pool is being shutdown.
|
||||
*/
|
||||
private boolean isStopping;
|
||||
|
||||
/**
|
||||
* List of PooledThread that are free for work.
|
||||
*/
|
||||
private Vector<PooledThread> freeList = new Vector<PooledThread>();
|
||||
|
||||
/**
|
||||
* List of PooledThread that are busy.
|
||||
*/
|
||||
private Vector<PooledThread> busyList = new Vector<PooledThread>();
|
||||
|
||||
/**
|
||||
* List holding queued work.
|
||||
*/
|
||||
private Vector<Work> workOverflowQueue = new Vector<Work>();
|
||||
|
||||
/**
|
||||
* Create and return a ThreadPool reading configuration from GlobalProperties.
|
||||
*/
|
||||
public static ThreadPool createThreadPool(String poolName) {
|
||||
|
||||
int min = GlobalProperties.getInt("threadpool." + poolName + ".min", 0);
|
||||
int max = GlobalProperties.getInt("threadpool." + poolName + ".max", 100);
|
||||
|
||||
int defaultIdleTime = GlobalProperties.getInt("threadpool.idletime", 60);
|
||||
long idle = 1000 * GlobalProperties.getInt("threadpool." + poolName + ".idletime", defaultIdleTime);
|
||||
|
||||
Integer priority = null;
|
||||
String threadPriority = GlobalProperties.get("threadpool." + poolName + ".priority", null);
|
||||
if (threadPriority != null) {
|
||||
priority = new Integer(threadPriority);
|
||||
}
|
||||
|
||||
return new ThreadPool(poolName, true, priority, min, max, idle);
|
||||
}
|
||||
|
||||
public ThreadPool(String poolName, boolean isDaemon, Integer threadPriority, int minSize, int maxSize, long maxIdleMillis) {
|
||||
this(poolName, isDaemon, threadPriority);
|
||||
this.minSize = minSize;
|
||||
this.maxSize = maxSize;
|
||||
this.maxIdleTime = maxIdleMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ThreadPool.
|
||||
*/
|
||||
public ThreadPool(String poolName, boolean isDaemon, Integer threadPriority) {
|
||||
|
||||
this.poolName = poolName;
|
||||
this.isDaemon = isDaemon;
|
||||
this.threadPriority = threadPriority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the pool is shutting down.
|
||||
*/
|
||||
public boolean isStopping() {
|
||||
synchronized (freeList) {
|
||||
return isStopping;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the thread pool.
|
||||
*/
|
||||
public String getName() {
|
||||
return poolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum size the pool should try to maintain.
|
||||
*/
|
||||
public void setMinSize(int minSize) {
|
||||
if (minSize > 0) {
|
||||
if (minSize > maxSize) {
|
||||
this.maxSize = minSize;
|
||||
}
|
||||
this.minSize = minSize;
|
||||
maintainPoolSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum size the pool should maintain.
|
||||
*/
|
||||
public int getMinSize() {
|
||||
return minSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum size the pool should grow to.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
if (maxSize > 0) {
|
||||
if (minSize > maxSize) {
|
||||
minSize = maxSize;
|
||||
}
|
||||
this.maxSize = maxSize;
|
||||
maintainPoolSize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size this pool can grow to.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the total number of busy and free threads in the pool.
|
||||
*/
|
||||
public int size() {
|
||||
return busyList.size() + freeList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of currently busy threads.
|
||||
*/
|
||||
public int getBusyCount() {
|
||||
return busyList.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign a task to the thread pool, specifing the options to wait or queue
|
||||
* the task if the pool is fully busy and can't grow.
|
||||
* <p>
|
||||
* When the pool is fully busy...
|
||||
* </p>
|
||||
* <p>
|
||||
* addToQueue=true -> work is added to queue, returns false<br>
|
||||
* addToQueue=false -> work is not done or queued, returns false<br>
|
||||
* </p>
|
||||
*
|
||||
* @param work
|
||||
* the runnable work to do.
|
||||
* @param addToQueueIfFull
|
||||
* If the pool is maxed out and this is true then it queues the
|
||||
* Runnable.
|
||||
*/
|
||||
public boolean assign(Runnable work, boolean addToQueueIfFull) {
|
||||
|
||||
if (stopThePool) {
|
||||
throw new RuntimeException("Pool is stopping... no more work please.");
|
||||
}
|
||||
|
||||
Work runWork = new Work(work);
|
||||
|
||||
// get the next available thread in the pool (block)
|
||||
PooledThread thread = getNextAvailableThread();
|
||||
if (thread != null) {
|
||||
// assign the work to that thread
|
||||
busyList.add(thread);
|
||||
thread.assignWork(runWork);
|
||||
return true;
|
||||
|
||||
} else {
|
||||
if (addToQueueIfFull) {
|
||||
runWork.setEnterQueueTime(System.currentTimeMillis());
|
||||
workOverflowQueue.add(runWork);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the thread from the pool. The thread should be stopped before it is
|
||||
* removed.
|
||||
*/
|
||||
protected void removeThread(PooledThread thread) {
|
||||
synchronized (freeList) {
|
||||
busyList.remove(thread);
|
||||
freeList.remove(thread);
|
||||
freeList.notify();
|
||||
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("PooledThread stopped [" + getName() + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fired when a Thread from the pool has finished, and can be put back into
|
||||
* the pool.
|
||||
*/
|
||||
protected void returnThread(PooledThread thread) {
|
||||
|
||||
synchronized (freeList) {
|
||||
|
||||
// deregister from the busyList
|
||||
busyList.remove(thread);
|
||||
|
||||
if (!workOverflowQueue.isEmpty()) {
|
||||
// get the first bit of work off the queue
|
||||
Work queuedWork = (Work) workOverflowQueue.remove(0);
|
||||
|
||||
// work out the queue time and counts etc
|
||||
queuedWork.setExitQueueTime(System.currentTimeMillis());
|
||||
busyList.add(thread);
|
||||
thread.assignWork(queuedWork);
|
||||
|
||||
} else {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("returnThread - add to freeList [" + thread + "]");
|
||||
}
|
||||
// put the thread back onto the available list
|
||||
freeList.add(thread);
|
||||
// tell shutdown() one has returned
|
||||
freeList.notify();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next available thread. Block until thread is available. NB: The
|
||||
* dispatcher is blocked but work can still be assigned to the dispatcher in a
|
||||
* non-blocking way
|
||||
*/
|
||||
private PooledThread getNextAvailableThread() {
|
||||
|
||||
synchronized (freeList) {
|
||||
if (!freeList.isEmpty()) {
|
||||
return (PooledThread) freeList.remove(0);
|
||||
}
|
||||
if (size() < maxSize) {
|
||||
return growPool(true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an Iterator of PooledThread that are currently running. You should
|
||||
* only use this for display. Use the getPooledThread() or interrupt() methods
|
||||
* to interrupt a particular thread.
|
||||
*
|
||||
* @return an Iterator of busy PooledThread's.
|
||||
*/
|
||||
public Iterator<PooledThread> getBusyThreads() {
|
||||
synchronized (freeList) {
|
||||
return busyList.iterator();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown the threadpool stopping all the threads. This will wait until any
|
||||
* busy threads have finished their assigned work.
|
||||
*/
|
||||
public void shutdown() {
|
||||
|
||||
synchronized (freeList) {
|
||||
if (isStopping) {
|
||||
logger.debug("already shutting down");
|
||||
}
|
||||
isStopping = true;
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ThreadPool [" + poolName + "] Shutting down; threadCount[" + size()+ "] busyCount[" + getBusyCount() + "]");
|
||||
}
|
||||
stopThePool = true;
|
||||
|
||||
while (!freeList.isEmpty()) {
|
||||
PooledThread thread = (PooledThread) freeList.remove(0);
|
||||
thread.stop();
|
||||
}
|
||||
|
||||
try {
|
||||
while (getBusyCount() > 0) {
|
||||
|
||||
String msg = "ThreadPool [" + poolName + "] has [" + getBusyCount()+ "] busy threads, waiting for those to finish.";
|
||||
logger.info(msg);
|
||||
|
||||
Iterator<PooledThread> busyThreads = getBusyThreads();
|
||||
while (busyThreads.hasNext()) {
|
||||
PooledThread busyThread = (PooledThread) busyThreads.next();
|
||||
String busymsg = "Busy thread [" + busyThread.getName() + "] work["+ busyThread.getWork() + "]";
|
||||
logger.info(busymsg);
|
||||
}
|
||||
|
||||
freeList.wait();
|
||||
PooledThread thread = (PooledThread) freeList.remove(0);
|
||||
logger.debug("wait finished on thread[" + thread.getName() + "]");
|
||||
if (thread != null) {
|
||||
thread.stop();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("Error during threadpool shutdown", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim or grow the pool leaving at least min free.
|
||||
*/
|
||||
protected void maintainPoolSize() {
|
||||
synchronized (freeList) {
|
||||
if (isStopping) {
|
||||
// don't bother as the pool is shutting down
|
||||
return;
|
||||
}
|
||||
|
||||
int numToStop = size() - minSize;
|
||||
if (numToStop > 0) {
|
||||
// should trim idle threads as we are over the minSize
|
||||
long usedAfter = System.currentTimeMillis() - maxIdleTime;
|
||||
ArrayList<PooledThread> stopList = new ArrayList<PooledThread>();
|
||||
Iterator<PooledThread> it = freeList.iterator();
|
||||
while (it.hasNext() && numToStop > 0) {
|
||||
PooledThread thread = (PooledThread) it.next();
|
||||
if (thread.getLastUsedTime() < usedAfter) {
|
||||
stopList.add(thread);
|
||||
numToStop--;
|
||||
}
|
||||
}
|
||||
Iterator<PooledThread> stopIt = stopList.iterator();
|
||||
while (stopIt.hasNext()) {
|
||||
PooledThread thread = (PooledThread) stopIt.next();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("trimming pool - stopping thread "+thread);
|
||||
}
|
||||
thread.stop();
|
||||
}
|
||||
}
|
||||
int numToAdd = minSize - size();
|
||||
if (numToAdd > 0) {
|
||||
// should add some more to the pool
|
||||
for (int i = 0; i < numToAdd; i++) {
|
||||
growPool(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt a named thread that is currently busy.
|
||||
* <p>
|
||||
* Returns the thread that was interrupted or null if the thread was not
|
||||
* found. If the thread was interrupted then it will automatically be stopped
|
||||
* and removed from the pool.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that it may take some time to actually interrupt the thread so an
|
||||
* immediate test to see if the thread stopped will probably be wrong.
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* ThreadPool test = ThreadPoolManager.getThreadPool("test");
|
||||
* PooledThread pt = test.interrupt("test.1");
|
||||
* if (pt == null) {
|
||||
* // the thread was not found, perhaps finished?
|
||||
* } else {
|
||||
* // give interrupt a little time to execute
|
||||
* Thread.sleep(1000);
|
||||
* boolean hasStopped = pt.isStopped();
|
||||
* //..
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* </p>
|
||||
*
|
||||
* @return the thread that was interrupted
|
||||
*/
|
||||
public PooledThread interrupt(String threadName) {
|
||||
PooledThread thread = getBusyThread(threadName);
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
return thread;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a thread using its name from the busy list. Returns null if the thread
|
||||
* is not found in the busy list.
|
||||
*/
|
||||
public PooledThread getBusyThread(String threadName) {
|
||||
synchronized (freeList) {
|
||||
Iterator<PooledThread> it = getBusyThreads();
|
||||
while (it.hasNext()) {
|
||||
PooledThread pt = (PooledThread) it.next();
|
||||
if (pt.getName().equals(threadName)) {
|
||||
return pt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Grow the pool with the option of either putting it on the available list,
|
||||
* or returning it.
|
||||
*/
|
||||
private PooledThread growPool(boolean andReturn) {
|
||||
|
||||
synchronized (freeList) {
|
||||
|
||||
String threadName = poolName + "." + uniqueThreadID++;
|
||||
PooledThread bgw = new PooledThread(this, threadName, isDaemon, threadPriority);
|
||||
bgw.start();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("ThreadPool grow created [" + threadName + "] size[" + size() + "]");
|
||||
}
|
||||
if (andReturn) {
|
||||
return bgw;
|
||||
} else {
|
||||
freeList.add(bgw);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum amount of time in millis that Threads can be idle before
|
||||
* they are trimmed.
|
||||
*/
|
||||
public long getMaxIdleTime() {
|
||||
return maxIdleTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maxiumium amount of time in millis that Threads can be idle before
|
||||
* they are trimed.
|
||||
*/
|
||||
public void setMaxIdleTime(long maxIdleTime) {
|
||||
this.maxIdleTime = maxIdleTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.lib.thread;
|
||||
|
||||
|
||||
/**
|
||||
* Used internally by the ThreadPool to wrap a Runnable that is
|
||||
* going to be run.
|
||||
*
|
||||
* <p>Used to maintains some useful times about the Runnable in terms of when
|
||||
* it was queued and then eventually run.</p>
|
||||
*/
|
||||
public class Work {
|
||||
|
||||
/**
|
||||
* Create a Runnable Work.
|
||||
*/
|
||||
public Work(Runnable runnable) {
|
||||
this.runnable = runnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the associated Runnable object.
|
||||
*/
|
||||
public Runnable getRunnable() {
|
||||
return runnable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time this work actually started.
|
||||
*/
|
||||
public long getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time this work actually started.
|
||||
*/
|
||||
public void setStartTime(long startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time this entered the queue.
|
||||
*/
|
||||
public long getEnterQueueTime() {
|
||||
return enterQueueTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time this entered the queue.
|
||||
*/
|
||||
public void setEnterQueueTime(long enterQueueTime) {
|
||||
this.enterQueueTime = enterQueueTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time this left the queue.
|
||||
*/
|
||||
public long getExitQueueTime() {
|
||||
return exitQueueTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time this work left the queue.
|
||||
*/
|
||||
public void setExitQueueTime(long exitQueueTime) {
|
||||
this.exitQueueTime = exitQueueTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as getDescription().
|
||||
*/
|
||||
public String toString() {
|
||||
return getDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description of this work.
|
||||
*/
|
||||
public String getDescription() {
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("Work[");
|
||||
if (runnable != null){
|
||||
sb.append(runnable.toString());
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Runnable runnable;
|
||||
|
||||
private long exitQueueTime;
|
||||
private long enterQueueTime;
|
||||
private long startTime;
|
||||
|
||||
};
|
||||
@@ -1,12 +0,0 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
|
||||
<TITLE>AvajeLib</TITLE>
|
||||
</HEAD>
|
||||
<Body BGCOLOR="#ffffff">
|
||||
ThreadPool service.
|
||||
<P>
|
||||
Service providing thread pooling for executing background tasks.
|
||||
</P>
|
||||
</Body>
|
||||
</HTML>
|
||||
@@ -1,13 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.persist;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.event.BeanPersistController;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestBean;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestCallableSql;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestOrmUpdate;
|
||||
import com.avaje.ebeaninternal.server.core.PersistRequestUpdateSql;
|
||||
import com.avaje.ebeaninternal.server.core.PstmtBatch;
|
||||
import com.avaje.ebeaninternal.server.core.*;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanManager;
|
||||
|
||||
/**
|
||||
@@ -32,19 +27,17 @@ public final class DefaultPersistExecute implements PersistExecute {
|
||||
/**
|
||||
* Default for whether to call getGeneratedKeys after batch insert.
|
||||
*/
|
||||
private final boolean defaultBatchGenKeys;
|
||||
private final boolean defaultBatchGenKeys = true;
|
||||
|
||||
/**
|
||||
* Construct this DmlPersistExecute.
|
||||
*/
|
||||
public DefaultPersistExecute(Binder binder, PstmtBatch pstmtBatch) {
|
||||
public DefaultPersistExecute(Binder binder, PstmtBatch pstmtBatch, int defaultBatchSize) {
|
||||
|
||||
this.exeOrmUpdate = new ExeOrmUpdate(binder, pstmtBatch);
|
||||
this.exeUpdateSql = new ExeUpdateSql(binder, pstmtBatch);
|
||||
this.exeCallableSql = new ExeCallableSql(binder, pstmtBatch);
|
||||
|
||||
this.defaultBatchGenKeys = GlobalProperties.getBoolean("batch.getgeneratedkeys", true);
|
||||
this.defaultBatchSize = GlobalProperties.getInt("batch.size", 20);
|
||||
this.defaultBatchSize = defaultBatchSize;
|
||||
}
|
||||
|
||||
public BatchControl createBatchControl(SpiTransaction t) {
|
||||
|
||||
@@ -79,7 +79,7 @@ public final class DefaultPersister implements Persister {
|
||||
this.server = server;
|
||||
this.updatesDeleteMissingChildren = server.getServerConfig().isUpdatesDeleteMissingChildren();
|
||||
this.beanDescriptorManager = descMgr;
|
||||
this.persistExecute = new DefaultPersistExecute(binder, pstmtBatch);
|
||||
this.persistExecute = new DefaultPersistExecute(binder, pstmtBatch, server.getServerConfig().getPersistBatchSize());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -182,7 +182,6 @@ public final class DefaultPersister implements Persister {
|
||||
}
|
||||
|
||||
req.commitTransIfRequired();
|
||||
return;
|
||||
|
||||
} catch (RuntimeException ex) {
|
||||
req.rollbackTransIfRequired();
|
||||
@@ -469,7 +468,7 @@ public final class DefaultPersister implements Persister {
|
||||
int rows = executeSqlUpdate(deleteById, t);
|
||||
|
||||
// Delete from the persistence context so that it can't be fetched again later
|
||||
PersistenceContext persistenceContext = ((SpiTransaction)t).getPersistenceContext();
|
||||
PersistenceContext persistenceContext = t.getPersistenceContext();
|
||||
if (idList != null) {
|
||||
for (Object idValue : idList) {
|
||||
persistenceContext.deleted(descriptor.getBeanType(), idValue);
|
||||
@@ -879,7 +878,7 @@ public final class DefaultPersister implements Persister {
|
||||
Collection<?> additions = null;
|
||||
Collection<?> deletions = null;
|
||||
|
||||
boolean vanillaCollection = (value instanceof BeanCollection<?> == false);
|
||||
boolean vanillaCollection = !(value instanceof BeanCollection<?>);
|
||||
|
||||
if (vanillaCollection || deleteMissingChildren) {
|
||||
// delete all intersection rows and then treat all
|
||||
|
||||
@@ -2,7 +2,6 @@ package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import com.avaje.ebean.QueryIterator;
|
||||
import com.avaje.ebean.bean.*;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.SpiExpressionList;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiQuery.Mode;
|
||||
@@ -45,7 +44,7 @@ public class CQuery<T> implements DbReadContext, CancelableQuery {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CQuery.class);
|
||||
|
||||
private static final int GLOBAL_ROW_LIMIT = GlobalProperties.getInt("query.globallimit",1000000);
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit","1000000"));
|
||||
|
||||
/**
|
||||
* The resultSet rows read.
|
||||
|
||||
@@ -1,15 +1,9 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.RawSql.ColumnMapping;
|
||||
import com.avaje.ebean.RawSql.ColumnMapping.Column;
|
||||
import com.avaje.ebean.RawSqlBuilder;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
|
||||
import com.avaje.ebean.config.dbplatform.SqlLimitRequest;
|
||||
import com.avaje.ebean.config.dbplatform.SqlLimitResponse;
|
||||
@@ -27,6 +21,10 @@ import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryDetail;
|
||||
import com.avaje.ebeaninternal.server.querydefn.OrmQueryLimitRequest;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Generates the SQL SELECT statements taking into account the physical
|
||||
* deployment properties.
|
||||
@@ -53,8 +51,8 @@ public class CQueryBuilder implements Constants {
|
||||
public CQueryBuilder(DatabasePlatform dbPlatform, Binder binder) {
|
||||
|
||||
this.binder = binder;
|
||||
this.tableAliasPlaceHolder = GlobalProperties.get("ebean.tableAliasPlaceHolder", "${ta}");
|
||||
this.columnAliasPrefix = GlobalProperties.get("ebean.columnAliasPrefix", "c");
|
||||
this.tableAliasPlaceHolder = dbPlatform.getTableAliasPlaceHolder();
|
||||
this.columnAliasPrefix = dbPlatform.getColumnAliasPrefix();
|
||||
this.sqlSelectBuilder = new RawSqlSelectClauseBuilder(dbPlatform, binder);
|
||||
|
||||
this.sqlLimiter = dbPlatform.getSqlLimiter();
|
||||
|
||||
+12
-21
@@ -1,21 +1,8 @@
|
||||
package com.avaje.ebeaninternal.server.query;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.SqlQueryListener;
|
||||
import com.avaje.ebean.SqlRow;
|
||||
import com.avaje.ebean.bean.BeanCollection;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.BindParams;
|
||||
import com.avaje.ebeaninternal.api.SpiSqlQuery;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
@@ -27,6 +14,12 @@ import com.avaje.ebeaninternal.server.persist.Binder;
|
||||
import com.avaje.ebeaninternal.server.transaction.TransactionManager;
|
||||
import com.avaje.ebeaninternal.server.type.DataBind;
|
||||
import com.avaje.ebeaninternal.server.util.BindParamsParser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Perform native sql fetches.
|
||||
@@ -35,7 +28,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(DefaultRelationalQueryEngine.class);
|
||||
|
||||
private final int defaultMaxRows;
|
||||
private static final int GLOBAL_ROW_LIMIT = Integer.valueOf(System.getProperty("ebean.query.globallimit","1000000"));
|
||||
|
||||
private final Binder binder;
|
||||
|
||||
@@ -43,7 +36,6 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
|
||||
public DefaultRelationalQueryEngine(Binder binder, String dbTrueValue) {
|
||||
this.binder = binder;
|
||||
this.defaultMaxRows = GlobalProperties.getInt("nativesql.defaultmaxrows",100000);
|
||||
this.dbTrueValue = dbTrueValue == null ? "true" : dbTrueValue;
|
||||
}
|
||||
|
||||
@@ -70,7 +62,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
try {
|
||||
|
||||
String bindLog = "";
|
||||
String[] propNames = null;
|
||||
String[] propNames;
|
||||
|
||||
synchronized (query) {
|
||||
if (query.isCancelled()){
|
||||
@@ -111,7 +103,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
int estimateCapacity = (int) initCap + 1;
|
||||
|
||||
// determine the maxRows limit
|
||||
int maxRows = defaultMaxRows;
|
||||
int maxRows = GLOBAL_ROW_LIMIT;
|
||||
if (query.getMaxRows() >= 1) {
|
||||
maxRows = query.getMaxRows();
|
||||
}
|
||||
@@ -130,7 +122,7 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
synchronized (query) {
|
||||
// synchronise for query.cancel() support
|
||||
if (!query.isCancelled()){
|
||||
bean = readRow(request, rset, propNames, estimateCapacity);
|
||||
bean = readRow(rset, propNames, estimateCapacity);
|
||||
}
|
||||
}
|
||||
if (bean != null){
|
||||
@@ -210,14 +202,13 @@ public class DefaultRelationalQueryEngine implements RelationalQueryEngine {
|
||||
propNames.add(columnName);
|
||||
}
|
||||
|
||||
return (String[]) propNames.toArray(new String[propNames.size()]);
|
||||
return propNames.toArray(new String[propNames.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the row from the ResultSet and return as a MapBean.
|
||||
*/
|
||||
protected SqlRow readRow(RelationalQueryRequest request, ResultSet rset,
|
||||
String[] propNames, int initialCapacity) throws SQLException {
|
||||
protected SqlRow readRow(ResultSet rset, String[] propNames, int initialCapacity) throws SQLException {
|
||||
|
||||
// by default a map will rehash on the 12th entry
|
||||
// it will be pretty common to have 12 or more entries so
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
package com.avaje.ebeaninternal.server.resource;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.DirectoryFinder;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.FileResourceSource;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.ResourceSource;
|
||||
import com.avaje.ebeaninternal.server.lib.resource.UrlResourceSource;
|
||||
import com.avaje.ebeaninternal.server.lib.util.NotFoundException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Creates a ResourceManager for a server depending on the avaje.properties.
|
||||
* <p>
|
||||
@@ -50,7 +46,7 @@ public class ResourceManagerFactory {
|
||||
|
||||
String dir = null;
|
||||
if (serverConfig.getAutofetchConfig() != null) {
|
||||
dir = serverConfig.getAutofetchConfig().getLogDirectoryWithEval();
|
||||
dir = serverConfig.getAutofetchConfig().getLogDirectory();
|
||||
}
|
||||
if (dir != null) {
|
||||
return new File(dir);
|
||||
@@ -75,18 +71,7 @@ public class ResourceManagerFactory {
|
||||
|
||||
// default for web application, override this for file system
|
||||
String defaultDir = serverConfig.getResourceDirectory();
|
||||
|
||||
|
||||
// the default... check if a webapp first...
|
||||
ServletContext sc = GlobalProperties.getServletContext();
|
||||
if (sc != null) {
|
||||
// servlet container so use ServletContext.getResource()
|
||||
if (defaultDir == null) {
|
||||
defaultDir = "WEB-INF/ebean";
|
||||
}
|
||||
return new UrlResourceSource(sc, defaultDir);
|
||||
|
||||
}
|
||||
// use File System directory
|
||||
return createFileSource(defaultDir);
|
||||
}
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class IndexEvent {
|
||||
|
||||
public static final int COMMIT_EVENT = 1;
|
||||
public static final int OPTIMISE_EVENT = 2;
|
||||
|
||||
private final int eventType;
|
||||
private final String indexName;
|
||||
|
||||
public IndexEvent(int eventType, String indexName) {
|
||||
this.eventType = eventType;
|
||||
this.indexName = indexName;
|
||||
}
|
||||
|
||||
public int getEventType() {
|
||||
return eventType;
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
public static IndexEvent readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
int eventType = dataInput.readInt();
|
||||
String indexName = dataInput.readUTF();
|
||||
return new IndexEvent(eventType, indexName);
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage msg = new BinaryMessage(indexName.length()+10);
|
||||
DataOutputStream os = msg.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_INDEX);
|
||||
os.writeInt(eventType);
|
||||
os.writeUTF(indexName);
|
||||
|
||||
msgList.add(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
public class IndexInvalidate {
|
||||
|
||||
private final String indexName;
|
||||
|
||||
public IndexInvalidate(String indexName) {
|
||||
this.indexName = indexName;
|
||||
}
|
||||
|
||||
public String getIndexName() {
|
||||
return indexName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hc = IndexInvalidate.class.hashCode();
|
||||
hc = hc * 31 + indexName.hashCode();
|
||||
return hc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o){
|
||||
if (o instanceof IndexInvalidate == false){
|
||||
return false;
|
||||
}
|
||||
return indexName.equals(((IndexInvalidate)o).indexName);
|
||||
}
|
||||
|
||||
public static IndexInvalidate readBinaryMessage(DataInput dataInput) throws IOException {
|
||||
|
||||
|
||||
String indexName = dataInput.readUTF();
|
||||
return new IndexInvalidate(indexName);
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
BinaryMessage msg = new BinaryMessage(indexName.length()+10);
|
||||
DataOutputStream os = msg.getOs();
|
||||
os.writeInt(BinaryMessage.TYPE_INDEX_INVALIDATE);
|
||||
os.writeUTF(indexName);
|
||||
|
||||
msgList.add(msg);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
import com.avaje.ebeaninternal.api.TransactionEvent;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventBeans;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable;
|
||||
@@ -14,6 +10,8 @@ import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Performs post commit processing using a background thread.
|
||||
* <p>
|
||||
@@ -36,8 +34,6 @@ public final class PostCommitProcessing {
|
||||
|
||||
private final BeanPersistIdMap beanPersistIdMap;
|
||||
|
||||
// private final BeanDeltaMap beanDeltaMap;
|
||||
|
||||
private final RemoteTransactionEvent remoteTransactionEvent;
|
||||
|
||||
private final DeleteByIdMap deleteByIdMap;
|
||||
@@ -45,7 +41,7 @@ public final class PostCommitProcessing {
|
||||
/**
|
||||
* Create for a TransactionManager and event.
|
||||
*/
|
||||
public PostCommitProcessing(ClusterManager clusterManager, TransactionManager manager, SpiTransaction transaction, TransactionEvent event) {
|
||||
public PostCommitProcessing(ClusterManager clusterManager, TransactionManager manager, TransactionEvent event) {
|
||||
|
||||
this.clusterManager = clusterManager;
|
||||
this.manager = manager;
|
||||
@@ -53,10 +49,7 @@ public final class PostCommitProcessing {
|
||||
this.event = event;
|
||||
this.deleteByIdMap = event.getDeleteByIdMap();
|
||||
this.persistBeanRequests = createPersistBeanRequests();
|
||||
|
||||
this.beanPersistIdMap = createBeanPersistIdMap();
|
||||
//this.beanDeltaMap = new BeanDeltaMap(event.getBeanDeltas());
|
||||
|
||||
this.remoteTransactionEvent = createRemoteTransactionEvent();
|
||||
}
|
||||
|
||||
@@ -87,8 +80,8 @@ public final class PostCommitProcessing {
|
||||
public void notifyCluster() {
|
||||
if (remoteTransactionEvent != null && !remoteTransactionEvent.isEmpty()) {
|
||||
// send the interesting events to the cluster
|
||||
if (manager.getClusterDebugLevel() > 0 || logger.isDebugEnabled()) {
|
||||
logger.info("Cluster Send: " + remoteTransactionEvent.toString());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cluster Send: {}", remoteTransactionEvent);
|
||||
}
|
||||
|
||||
clusterManager.broadcast(remoteTransactionEvent);
|
||||
@@ -147,12 +140,6 @@ public final class PostCommitProcessing {
|
||||
|
||||
RemoteTransactionEvent remoteTransactionEvent = new RemoteTransactionEvent(serverName);
|
||||
|
||||
// if (beanDeltaMap != null) {
|
||||
// for (BeanDeltaList deltaList : beanDeltaMap.deltaLists()) {
|
||||
// remoteTransactionEvent.addBeanDeltaList(deltaList);
|
||||
// }
|
||||
// }
|
||||
|
||||
if (beanPersistIdMap != null) {
|
||||
for (BeanPersistIds beanPersist : beanPersistIdMap.values()) {
|
||||
remoteTransactionEvent.addBeanPersistIds(beanPersist);
|
||||
@@ -170,13 +157,6 @@ public final class PostCommitProcessing {
|
||||
}
|
||||
}
|
||||
|
||||
Set<IndexInvalidate> indexInvalidations = event.getIndexInvalidations();
|
||||
if (indexInvalidations != null) {
|
||||
for (IndexInvalidate indexInvalidate : indexInvalidations) {
|
||||
remoteTransactionEvent.addIndexInvalidate(indexInvalidate);
|
||||
}
|
||||
}
|
||||
|
||||
return remoteTransactionEvent;
|
||||
}
|
||||
|
||||
|
||||
+4
-44
@@ -1,15 +1,13 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.avaje.ebeaninternal.api.SpiEbeanServer;
|
||||
import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
|
||||
import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class RemoteTransactionEvent implements Runnable {
|
||||
|
||||
private List<BeanPersistIds> beanPersistList = new ArrayList<BeanPersistIds>();
|
||||
@@ -19,10 +17,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
private List<BeanDeltaList> beanDeltaLists;
|
||||
|
||||
private BeanDeltaMap beanDeltaMap;
|
||||
|
||||
private List<IndexEvent> indexEventList;
|
||||
|
||||
private Set<IndexInvalidate> indexInvalidations;
|
||||
|
||||
private DeleteByIdMap deleteByIdMap;
|
||||
|
||||
@@ -56,12 +50,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
if (indexInvalidations != null){
|
||||
for (IndexInvalidate indexInvalidate : indexInvalidations) {
|
||||
indexInvalidate.writeBinaryMessage(msgList);
|
||||
}
|
||||
}
|
||||
|
||||
if (tableList != null){
|
||||
for (int i = 0; i < tableList.size(); i++) {
|
||||
tableList.get(i).writeBinaryMessage(msgList);
|
||||
@@ -85,12 +73,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
beanDeltaLists.get(i).writeBinaryMessage(msgList);
|
||||
}
|
||||
}
|
||||
|
||||
if (indexEventList != null){
|
||||
for (int i = 0; i < indexEventList.size(); i++) {
|
||||
indexEventList.get(i).writeBinaryMessage(msgList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
@@ -101,13 +83,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
beanPersistList.add(beanPersist);
|
||||
}
|
||||
|
||||
public void addIndexInvalidate(IndexInvalidate indexInvalidate){
|
||||
if (indexInvalidations == null){
|
||||
indexInvalidations = new HashSet<IndexInvalidate>();
|
||||
}
|
||||
indexInvalidations.add(indexInvalidate);
|
||||
}
|
||||
|
||||
public void addTableIUD(TableIUD tableIud){
|
||||
if (tableList == null){
|
||||
tableList = new ArrayList<TableIUD>(4);
|
||||
@@ -129,13 +104,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
beanDeltaMap.addBeanDelta(beanDelta);
|
||||
}
|
||||
|
||||
public void addIndexEvent(IndexEvent indexEvent){
|
||||
if (indexEventList == null){
|
||||
indexEventList = new ArrayList<IndexEvent>(2);
|
||||
}
|
||||
indexEventList.add(indexEvent);
|
||||
}
|
||||
|
||||
public String getServerName() {
|
||||
return serverName;
|
||||
}
|
||||
@@ -156,14 +124,6 @@ public class RemoteTransactionEvent implements Runnable {
|
||||
this.deleteByIdMap = deleteByIdMap;
|
||||
}
|
||||
|
||||
public Set<IndexInvalidate> getIndexInvalidations() {
|
||||
return indexInvalidations;
|
||||
}
|
||||
|
||||
public List<IndexEvent> getIndexEventList() {
|
||||
return indexEventList;
|
||||
}
|
||||
|
||||
public List<TableIUD> getTableIUDList() {
|
||||
return tableList;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.transaction;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.BackgroundExecutor;
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebean.config.ServerConfig;
|
||||
import com.avaje.ebean.event.TransactionEventListener;
|
||||
import com.avaje.ebeaninternal.api.SpiTransaction;
|
||||
@@ -24,6 +11,16 @@ import com.avaje.ebeaninternal.server.cluster.ClusterManager;
|
||||
import com.avaje.ebeaninternal.server.core.BootupClasses;
|
||||
import com.avaje.ebeaninternal.server.deploy.BeanDescriptorManager;
|
||||
import com.avaje.ebeaninternal.server.lib.sql.DataSourcePool;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.persistence.PersistenceException;
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Manages transactions.
|
||||
@@ -97,8 +94,6 @@ public class TransactionManager {
|
||||
* Id's for transaction logging.
|
||||
*/
|
||||
protected AtomicLong transactionCounter = new AtomicLong(1000);
|
||||
|
||||
protected int clusterDebugLevel;
|
||||
|
||||
protected final BulkEventListenerMap bulkEventListenerMap;
|
||||
|
||||
@@ -119,16 +114,12 @@ public class TransactionManager {
|
||||
|
||||
List<TransactionEventListener> transactionEventListeners = bootupClasses.getTransactionEventListeners();
|
||||
this.transactionEventListeners = transactionEventListeners.toArray(new TransactionEventListener[transactionEventListeners.size()]);
|
||||
|
||||
// log some transaction events using a java util logger
|
||||
this.clusterDebugLevel = GlobalProperties.getInt("ebean.cluster.debuglevel", 0);
|
||||
|
||||
|
||||
this.defaultBatchMode = config.isPersistBatching();
|
||||
this.prefix = "";
|
||||
this.externalTransPrefix = "e";
|
||||
|
||||
this.prefix = GlobalProperties.get("transaction.prefix", "");
|
||||
this.externalTransPrefix = GlobalProperties.get("transaction.prefix", "e");
|
||||
|
||||
String value = GlobalProperties.get("transaction.onqueryonly", "CLOSE").toUpperCase().trim();
|
||||
String value = System.getProperty("ebean.transaction.onqueryonly", "CLOSE").toUpperCase().trim();
|
||||
this.onQueryOnly = getOnQueryOnly(value, dataSource);
|
||||
|
||||
initialiseHeartbeat();
|
||||
@@ -219,20 +210,6 @@ public class TransactionManager {
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the cluster debug level.
|
||||
*/
|
||||
public int getClusterDebugLevel() {
|
||||
return clusterDebugLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cluster debug level.
|
||||
*/
|
||||
public void setClusterDebugLevel(int clusterDebugLevel) {
|
||||
this.clusterDebugLevel = clusterDebugLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the type of behavior to use when closing a transaction that was used to query data only.
|
||||
*/
|
||||
@@ -416,7 +393,7 @@ public class TransactionManager {
|
||||
TXN_LOGGER.debug(transaction.getLogPrefix()+"Commit");
|
||||
}
|
||||
|
||||
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, transaction, transaction.getEvent());
|
||||
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, transaction.getEvent());
|
||||
|
||||
postCommit.notifyLocalCacheIndex();
|
||||
postCommit.notifyCluster();
|
||||
@@ -445,7 +422,7 @@ public class TransactionManager {
|
||||
TransactionEvent event = new TransactionEvent();
|
||||
event.add(tableEvents);
|
||||
|
||||
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, null, event);
|
||||
PostCommitProcessing postCommit = new PostCommitProcessing(clusterManager, this, event);
|
||||
|
||||
// invalidate parts of local cache and index
|
||||
postCommit.notifyLocalCacheIndex();
|
||||
@@ -458,8 +435,8 @@ public class TransactionManager {
|
||||
*/
|
||||
public void remoteTransactionEvent(RemoteTransactionEvent remoteEvent) {
|
||||
|
||||
if (clusterDebugLevel > 0 || logger.isDebugEnabled()) {
|
||||
logger.info("Cluster Received: " + remoteEvent.toString());
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Cluster Received: " + remoteEvent.toString());
|
||||
}
|
||||
|
||||
List<TableIUD> tableIUDList = remoteEvent.getTableIUDList();
|
||||
|
||||
@@ -1,30 +1,19 @@
|
||||
package com.avaje.ebeaninternal.server.util;
|
||||
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.*;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import com.avaje.ebean.config.GlobalProperties;
|
||||
import com.avaje.ebeaninternal.api.ClassUtil;
|
||||
|
||||
/**
|
||||
* Can search the class path for classes using a ClassPathSearchMatcher. A
|
||||
* ClassPathSearch should only be used once in a single threaded manor. It is
|
||||
@@ -55,22 +44,21 @@ public class ClassPathSearch {
|
||||
|
||||
private ArrayList<URI> scannedUris = new ArrayList<URI>();
|
||||
|
||||
public ClassPathSearch(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher) {
|
||||
public ClassPathSearch(ClassLoader classLoader, ClassPathSearchFilter filter, ClassPathSearchMatcher matcher, String classPathReaderClassName) {
|
||||
this.classLoader = classLoader;
|
||||
this.filter = filter;
|
||||
this.matcher = matcher;
|
||||
initClassPaths();
|
||||
initClassPaths(classPathReaderClassName);
|
||||
}
|
||||
|
||||
private void initClassPaths() {
|
||||
private void initClassPaths(String classPathReaderCN) {
|
||||
|
||||
try {
|
||||
|
||||
String cn = GlobalProperties.get("ebean.classpathreader", null);
|
||||
if (cn != null) {
|
||||
if (classPathReaderCN != null) {
|
||||
// use a user defined classPathReader
|
||||
logger.info("Using [" + cn + "] to read the searchable class path");
|
||||
classPathReader = (ClassPathReader) ClassUtil.newInstance(cn, this.getClass());
|
||||
logger.info("Using [" + classPathReaderCN + "] to read the searchable class path");
|
||||
classPathReader = (ClassPathReader) ClassUtil.newInstance(classPathReaderCN, this.getClass());
|
||||
}
|
||||
|
||||
Object[] rawClassPaths = classPathReader.readPath(classLoader);
|
||||
|
||||
Reference in New Issue
Block a user