Refactor properties bootup, remove GlobalProperties and allow ServerConfig.loadFromProperties()

This commit is contained in:
rbygrave
2014-11-30 17:08:02 +13:00
parent fe65a0ccb9
commit 370267ab6f
105 changed files with 3772 additions and 3963 deletions
@@ -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);
}
@@ -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) {
@@ -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);
}
@@ -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();
}
}
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;
}
@@ -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);
}
}
}
@@ -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();
@@ -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;
}
@@ -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);