diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDelta.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDelta.java
index c5ee4b37c..320b0620b 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDelta.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDelta.java
@@ -1,103 +1,103 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.DataInput;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.avaje.ebean.bean.EntityBean;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-import com.avaje.ebeaninternal.server.deploy.BeanProperty;
-
-public class BeanDelta {
-
- private final List properties;
-
- private final BeanDescriptor> beanDescriptor;
-
- private final Object id;
-
- public BeanDelta(BeanDescriptor> beanDescriptor, Object id) {
- this.beanDescriptor = beanDescriptor;
- this.id = id;
- this.properties = new ArrayList();
- }
-
- public BeanDescriptor> getBeanDescriptor() {
- return beanDescriptor;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("BeanDelta[");
- sb.append(beanDescriptor.getName()).append(":");
- sb.append(properties);
- sb.append("]");
- return sb.toString();
- }
-
- public Object getId() {
- return id;
- }
-
- public void add(BeanProperty beanProperty, Object value) {
- this.properties.add(new BeanDeltaProperty(beanProperty, value));
- }
-
- public void add(BeanDeltaProperty propertyDelta) {
- this.properties.add(propertyDelta);
- }
-
- public void apply(EntityBean bean) {
-
- for (int i = 0; i < properties.size(); i++) {
- properties.get(i).apply(bean);
- }
- }
-
- /**
- * Read and return a BeanDelta from the binary input.
- */
- public static BeanDelta readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
-
- String descriptorId = dataInput.readUTF();
- BeanDescriptor> desc = server.getBeanDescriptorById(descriptorId);
- Object id = desc.getIdBinder().readData(dataInput);
- BeanDelta bp = new BeanDelta(desc, id);
-
- int count = dataInput.readInt();
- for (int i = 0; i < count; i++) {
- String propName = dataInput.readUTF();
- BeanProperty beanProperty = desc.getBeanProperty(propName);
- Object value = beanProperty.getScalarType().readData(dataInput);
- bp.add(beanProperty, value);
- }
- return bp;
- }
-
- /**
- * Write this bean delta in binary message format.
- */
- public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
-
- BinaryMessage m = new BinaryMessage(50);
-
- DataOutputStream os = m.getOs();
- os.writeInt(BinaryMessage.TYPE_BEANDELTA);
- os.writeUTF(beanDescriptor.getDescriptorId());
-
- beanDescriptor.getIdBinder().writeData(os, id);
- os.writeInt(properties.size());
-
- for (int i = 0; i < properties.size(); i++) {
- properties.get(i).writeBinaryMessage(m);
- }
-
- os.flush();
- msgList.add(m);
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.avaje.ebean.bean.EntityBean;
+import com.avaje.ebeaninternal.api.SpiEbeanServer;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+import com.avaje.ebeaninternal.server.deploy.BeanProperty;
+
+public class BeanDelta {
+
+ private final List properties;
+
+ private final BeanDescriptor> beanDescriptor;
+
+ private final Object id;
+
+ public BeanDelta(BeanDescriptor> beanDescriptor, Object id) {
+ this.beanDescriptor = beanDescriptor;
+ this.id = id;
+ this.properties = new ArrayList();
+ }
+
+ public BeanDescriptor> getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("BeanDelta[");
+ sb.append(beanDescriptor.getName()).append(":");
+ sb.append(properties);
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public Object getId() {
+ return id;
+ }
+
+ public void add(BeanProperty beanProperty, Object value) {
+ this.properties.add(new BeanDeltaProperty(beanProperty, value));
+ }
+
+ public void add(BeanDeltaProperty propertyDelta) {
+ this.properties.add(propertyDelta);
+ }
+
+ public void apply(EntityBean bean) {
+
+ for (int i = 0; i < properties.size(); i++) {
+ properties.get(i).apply(bean);
+ }
+ }
+
+ /**
+ * Read and return a BeanDelta from the binary input.
+ */
+ public static BeanDelta readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
+
+ String descriptorId = dataInput.readUTF();
+ BeanDescriptor> desc = server.getBeanDescriptorById(descriptorId);
+ Object id = desc.getIdBinder().readData(dataInput);
+ BeanDelta bp = new BeanDelta(desc, id);
+
+ int count = dataInput.readInt();
+ for (int i = 0; i < count; i++) {
+ String propName = dataInput.readUTF();
+ BeanProperty beanProperty = desc.getBeanProperty(propName);
+ Object value = beanProperty.getScalarType().readData(dataInput);
+ bp.add(beanProperty, value);
+ }
+ return bp;
+ }
+
+ /**
+ * Write this bean delta in binary message format.
+ */
+ public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
+
+ BinaryMessage m = new BinaryMessage(50);
+
+ DataOutputStream os = m.getOs();
+ os.writeInt(BinaryMessage.TYPE_BEANDELTA);
+ os.writeUTF(beanDescriptor.getDescriptorId());
+
+ beanDescriptor.getIdBinder().writeData(os, id);
+ os.writeInt(properties.size());
+
+ for (int i = 0; i < properties.size(); i++) {
+ properties.get(i).writeBinaryMessage(m);
+ }
+
+ os.flush();
+ msgList.add(m);
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaList.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaList.java
index 1cdbb7f52..6b6dccca7 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaList.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaList.java
@@ -1,42 +1,42 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-
-public class BeanDeltaList {
-
- private final BeanDescriptor> beanDescriptor;
-
- private final List deltaBeans = new ArrayList();
-
- public BeanDeltaList(BeanDescriptor> beanDescriptor) {
- this.beanDescriptor = beanDescriptor;
- }
-
- public String toString() {
- return deltaBeans.toString();
- }
-
- public BeanDescriptor> getBeanDescriptor() {
- return beanDescriptor;
- }
-
- public void add(BeanDelta b) {
- deltaBeans.add(b);
- }
-
- public List getDeltaBeans() {
- return deltaBeans;
- }
-
- public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
- for (int i = 0; i < deltaBeans.size(); i++) {
- deltaBeans.get(i).writeBinaryMessage(msgList);
- }
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+
+public class BeanDeltaList {
+
+ private final BeanDescriptor> beanDescriptor;
+
+ private final List deltaBeans = new ArrayList();
+
+ public BeanDeltaList(BeanDescriptor> beanDescriptor) {
+ this.beanDescriptor = beanDescriptor;
+ }
+
+ public String toString() {
+ return deltaBeans.toString();
+ }
+
+ public BeanDescriptor> getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ public void add(BeanDelta b) {
+ deltaBeans.add(b);
+ }
+
+ public List getDeltaBeans() {
+ return deltaBeans;
+ }
+
+ public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
+ for (int i = 0; i < deltaBeans.size(); i++) {
+ deltaBeans.get(i).writeBinaryMessage(msgList);
+ }
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaMap.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaMap.java
index 444d84dd1..0987c2cf6 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaMap.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaMap.java
@@ -1,48 +1,48 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-
-public class BeanDeltaMap {
-
- private Map deltaMap = new HashMap();
-
- public BeanDeltaMap() {
- }
-
- public BeanDeltaMap(List deltaBeans) {
- if (deltaBeans != null){
- for (int i = 0; i < deltaBeans.size(); i++) {
- BeanDelta deltaBean = deltaBeans.get(i);
- addBeanDelta(deltaBean);
- }
- }
- }
-
- public String toString() {
- return deltaMap.values().toString();
- }
-
- public void addBeanDelta(BeanDelta beanDelta){
- BeanDescriptor> d = beanDelta.getBeanDescriptor();
- BeanDeltaList list = getDeltaBeanList(d);
- list.add(beanDelta);
- }
-
- public Collection deltaLists() {
- return deltaMap.values();
- }
-
- private BeanDeltaList getDeltaBeanList(BeanDescriptor> d) {
- BeanDeltaList deltaList = deltaMap.get(d.getFullName());
- if (deltaList == null){
- deltaList = new BeanDeltaList(d);
- deltaMap.put(d.getFullName(), deltaList);
- }
- return deltaList;
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+
+public class BeanDeltaMap {
+
+ private Map deltaMap = new HashMap();
+
+ public BeanDeltaMap() {
+ }
+
+ public BeanDeltaMap(List deltaBeans) {
+ if (deltaBeans != null){
+ for (int i = 0; i < deltaBeans.size(); i++) {
+ BeanDelta deltaBean = deltaBeans.get(i);
+ addBeanDelta(deltaBean);
+ }
+ }
+ }
+
+ public String toString() {
+ return deltaMap.values().toString();
+ }
+
+ public void addBeanDelta(BeanDelta beanDelta){
+ BeanDescriptor> d = beanDelta.getBeanDescriptor();
+ BeanDeltaList list = getDeltaBeanList(d);
+ list.add(beanDelta);
+ }
+
+ public Collection deltaLists() {
+ return deltaMap.values();
+ }
+
+ private BeanDeltaList getDeltaBeanList(BeanDescriptor> d) {
+ BeanDeltaList deltaList = deltaMap.get(d.getFullName());
+ if (deltaList == null){
+ deltaList = new BeanDeltaList(d);
+ deltaMap.put(d.getFullName(), deltaList);
+ }
+ return deltaList;
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaProperty.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaProperty.java
index 316c33f1a..2085af801 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaProperty.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanDeltaProperty.java
@@ -1,36 +1,36 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-import com.avaje.ebean.bean.EntityBean;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
-import com.avaje.ebeaninternal.server.deploy.BeanProperty;
-
-public class BeanDeltaProperty {
-
- private final BeanProperty beanProperty;
-
- private final Object value;
-
- public BeanDeltaProperty(BeanProperty beanProperty, Object value) {
- this.beanProperty = beanProperty;
- this.value = value;
- }
-
- public String toString() {
- return beanProperty.getName()+":"+value;
- }
-
- public void apply(EntityBean bean) {
- beanProperty.setValue(bean, value);
- }
-
- public void writeBinaryMessage(BinaryMessage m) throws IOException {
-
- DataOutputStream os = m.getOs();
- os.writeUTF(beanProperty.getName());
- beanProperty.getScalarType().writeData(os, value);
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+import com.avaje.ebean.bean.EntityBean;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
+import com.avaje.ebeaninternal.server.deploy.BeanProperty;
+
+public class BeanDeltaProperty {
+
+ private final BeanProperty beanProperty;
+
+ private final Object value;
+
+ public BeanDeltaProperty(BeanProperty beanProperty, Object value) {
+ this.beanProperty = beanProperty;
+ this.value = value;
+ }
+
+ public String toString() {
+ return beanProperty.getName()+":"+value;
+ }
+
+ public void apply(EntityBean bean) {
+ beanProperty.setValue(bean, value);
+ }
+
+ public void writeBinaryMessage(BinaryMessage m) throws IOException {
+
+ DataOutputStream os = m.getOs();
+ os.writeUTF(beanProperty.getName());
+ beanProperty.getScalarType().writeData(os, value);
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdate.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdate.java
index 922e048b1..519ddb8ed 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdate.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdate.java
@@ -1,24 +1,24 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.Serializable;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-
-public class BeanPathUpdate {
-
- private final Map map = new LinkedHashMap();
-
- public void add(BeanDescriptor> desc, String path, Object id) {
-
- String key = desc.getFullName()+":"+path;
- BeanPathUpdateIds pathIds = map.get(key);
- if (pathIds == null){
- pathIds = new BeanPathUpdateIds(desc, path);
- map.put(key, pathIds);
- }
- pathIds.addId((Serializable)id);
-
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.Serializable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+
+public class BeanPathUpdate {
+
+ private final Map map = new LinkedHashMap();
+
+ public void add(BeanDescriptor> desc, String path, Object id) {
+
+ String key = desc.getFullName()+":"+path;
+ BeanPathUpdateIds pathIds = map.get(key);
+ if (pathIds == null){
+ pathIds = new BeanPathUpdateIds(desc, path);
+ map.put(key, pathIds);
+ }
+ pathIds.addId((Serializable)id);
+
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdateIds.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdateIds.java
index 59f2176e0..1f861162c 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdateIds.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPathUpdateIds.java
@@ -1,144 +1,144 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.DataInput;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
-
-public class BeanPathUpdateIds {
-
- private transient BeanDescriptor> beanDescriptor;
-
- private final String descriptorId;
-
- private String path;
-
- private ArrayList ids;
-
- /**
- * Create the payload.
- */
- public BeanPathUpdateIds(BeanDescriptor> desc, String path) {
- this.beanDescriptor = desc;
- this.descriptorId = desc.getDescriptorId();
- this.path = path;
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (beanDescriptor != null) {
- sb.append(beanDescriptor.getFullName());
- } else {
- sb.append("descId:").append(descriptorId);
- }
- sb.append(" path:").append(path);
- sb.append(" ids:").append(ids);
- return sb.toString();
- }
-
- public static BeanPathUpdateIds readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
-
- String descriptorId = dataInput.readUTF();
- String path = dataInput.readUTF();
- BeanDescriptor> desc = server.getBeanDescriptorById(descriptorId);
- BeanPathUpdateIds bp = new BeanPathUpdateIds(desc, path);
- bp.read(dataInput);
- return bp;
- }
-
- private void read(DataInput dataInput) throws IOException {
-
- IdBinder idBinder = beanDescriptor.getIdBinder();
- ids = readIdList(dataInput, idBinder);
- }
-
-
- private ArrayList readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
-
- int count = dataInput.readInt();
- if (count < 1) {
- return null;
- }
- ArrayList idList = new ArrayList(count);
- for (int i = 0; i < count; i++) {
- Object id = idBinder.readData(dataInput);
- idList.add((Serializable) id);
- }
- return idList;
- }
-
- /**
- * Write the contents into a BinaryMessage form.
- *
- * For a RemoteBeanPersist with a large number of id's note that this is
- * broken up into many BinaryMessages each with a maximum of 100 ids. This
- * enables the contents of a large RemoteTransactionEvent to be split up
- * across multiple Packets.
- *
- */
- public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
-
- IdBinder idBinder = beanDescriptor.getIdBinder();
-
- int count = ids == null ? 0 : ids.size();
- if (count > 0) {
- int loop = 0;
- int i = 0;
- int eof = ids.size();
- do {
- ++loop;
- int endOfLoop = Math.min(eof, loop * 100);
-
- BinaryMessage m = new BinaryMessage(endOfLoop * 4 + 20);
-
- DataOutputStream os = m.getOs();
- os.writeInt(BinaryMessage.TYPE_BEANPATHUPDATE);
- os.writeUTF(descriptorId);
- os.writeUTF(path);
- os.writeInt(count);
-
- for (; i < endOfLoop; i++) {
- Serializable idValue = ids.get(i);
- idBinder.writeData(os, idValue);
- }
-
- os.flush();
- msgList.add(m);
-
- } while (i < eof);
- }
- }
-
- public void addId(Serializable id) {
- ids.add(id);
- }
-
-
- public BeanDescriptor> getBeanDescriptor() {
- return beanDescriptor;
- }
-
- /**
- * Return the Descriptor Id. A more compact alternative to using the
- * beanType.
- */
- public String getDescriptorId() {
- return descriptorId;
- }
-
- public String getPath() {
- return path;
- }
-
- public List getIds() {
- return ids;
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.avaje.ebeaninternal.api.SpiEbeanServer;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
+
+public class BeanPathUpdateIds {
+
+ private transient BeanDescriptor> beanDescriptor;
+
+ private final String descriptorId;
+
+ private String path;
+
+ private ArrayList ids;
+
+ /**
+ * Create the payload.
+ */
+ public BeanPathUpdateIds(BeanDescriptor> desc, String path) {
+ this.beanDescriptor = desc;
+ this.descriptorId = desc.getDescriptorId();
+ this.path = path;
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (beanDescriptor != null) {
+ sb.append(beanDescriptor.getFullName());
+ } else {
+ sb.append("descId:").append(descriptorId);
+ }
+ sb.append(" path:").append(path);
+ sb.append(" ids:").append(ids);
+ return sb.toString();
+ }
+
+ public static BeanPathUpdateIds readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
+
+ String descriptorId = dataInput.readUTF();
+ String path = dataInput.readUTF();
+ BeanDescriptor> desc = server.getBeanDescriptorById(descriptorId);
+ BeanPathUpdateIds bp = new BeanPathUpdateIds(desc, path);
+ bp.read(dataInput);
+ return bp;
+ }
+
+ private void read(DataInput dataInput) throws IOException {
+
+ IdBinder idBinder = beanDescriptor.getIdBinder();
+ ids = readIdList(dataInput, idBinder);
+ }
+
+
+ private ArrayList readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
+
+ int count = dataInput.readInt();
+ if (count < 1) {
+ return null;
+ }
+ ArrayList idList = new ArrayList(count);
+ for (int i = 0; i < count; i++) {
+ Object id = idBinder.readData(dataInput);
+ idList.add((Serializable) id);
+ }
+ return idList;
+ }
+
+ /**
+ * Write the contents into a BinaryMessage form.
+ *
+ * For a RemoteBeanPersist with a large number of id's note that this is
+ * broken up into many BinaryMessages each with a maximum of 100 ids. This
+ * enables the contents of a large RemoteTransactionEvent to be split up
+ * across multiple Packets.
+ *
+ */
+ public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
+
+ IdBinder idBinder = beanDescriptor.getIdBinder();
+
+ int count = ids == null ? 0 : ids.size();
+ if (count > 0) {
+ int loop = 0;
+ int i = 0;
+ int eof = ids.size();
+ do {
+ ++loop;
+ int endOfLoop = Math.min(eof, loop * 100);
+
+ BinaryMessage m = new BinaryMessage(endOfLoop * 4 + 20);
+
+ DataOutputStream os = m.getOs();
+ os.writeInt(BinaryMessage.TYPE_BEANPATHUPDATE);
+ os.writeUTF(descriptorId);
+ os.writeUTF(path);
+ os.writeInt(count);
+
+ for (; i < endOfLoop; i++) {
+ Serializable idValue = ids.get(i);
+ idBinder.writeData(os, idValue);
+ }
+
+ os.flush();
+ msgList.add(m);
+
+ } while (i < eof);
+ }
+ }
+
+ public void addId(Serializable id) {
+ ids.add(id);
+ }
+
+
+ public BeanDescriptor> getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ /**
+ * Return the Descriptor Id. A more compact alternative to using the
+ * beanType.
+ */
+ public String getDescriptorId() {
+ return descriptorId;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public List getIds() {
+ return ids;
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIdMap.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIdMap.java
index 0f295bdad..b92ed0e6d 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIdMap.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIdMap.java
@@ -1,50 +1,50 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import com.avaje.ebeaninternal.server.core.PersistRequest;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-
-/**
- * Organises the individual bean persist requests by type.
- */
-public final class BeanPersistIdMap {
-
- private final Map beanMap = new LinkedHashMap();
-
- public String toString() {
- return beanMap.toString();
- }
-
- public boolean isEmpty() {
- return beanMap.isEmpty();
- }
-
- public Collection values() {
- return beanMap.values();
- }
-
- /**
- * Add a Insert Update or Delete payload.
- */
- public void add(BeanDescriptor> desc, PersistRequest.Type type, Object id) {
-
- BeanPersistIds r = getPersistIds(desc);
- r.addId(type, (Serializable)id);
- }
-
- private BeanPersistIds getPersistIds(BeanDescriptor> desc) {
- String beanType = desc.getFullName();
- BeanPersistIds r = beanMap.get(beanType);
- if (r == null){
- r = new BeanPersistIds(desc);
- beanMap.put(beanType, r);
- }
- return r;
- }
-
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.avaje.ebeaninternal.server.core.PersistRequest;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+
+/**
+ * Organises the individual bean persist requests by type.
+ */
+public final class BeanPersistIdMap {
+
+ private final Map beanMap = new LinkedHashMap();
+
+ public String toString() {
+ return beanMap.toString();
+ }
+
+ public boolean isEmpty() {
+ return beanMap.isEmpty();
+ }
+
+ public Collection values() {
+ return beanMap.values();
+ }
+
+ /**
+ * Add a Insert Update or Delete payload.
+ */
+ public void add(BeanDescriptor> desc, PersistRequest.Type type, Object id) {
+
+ BeanPersistIds r = getPersistIds(desc);
+ r.addId(type, (Serializable)id);
+ }
+
+ private BeanPersistIds getPersistIds(BeanDescriptor> desc) {
+ String beanType = desc.getFullName();
+ BeanPersistIds r = beanMap.get(beanType);
+ if (r == null){
+ r = new BeanPersistIds(desc);
+ beanMap.put(beanType, r);
+ }
+ return r;
+ }
+
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
index 57626e88c..d4d242cb4 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/BeanPersistIds.java
@@ -1,288 +1,288 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.DataInput;
-import java.io.DataOutputStream;
-import java.io.IOException;
-import java.io.Serializable;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.avaje.ebean.event.BeanPersistListener;
-import com.avaje.ebeaninternal.api.SpiEbeanServer;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
-import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
-import com.avaje.ebeaninternal.server.core.PersistRequest;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
-
-/**
- * Wraps the information representing a Inserted Updated or Deleted Bean.
- *
- * This information is broadcast across the cluster so that remote BeanListeners
- * are notified of the inserts updates and deletes that occured.
- *
- *
- * You control it the data is broadcast and what data is broadcast by the
- * BeanListener.getClusterData() method. It is guessed that often just the Id
- * property or perhaps a few properties in a Map will be broadcast to reduce the
- * size of data sent around the network.
- *
- * For a RemoteBeanPersist with a large number of id's note that this is
- * broken up into many BinaryMessages each with a maximum of 100 ids. This
- * enables the contents of a large RemoteTransactionEvent to be split up
- * across multiple Packets.
- *
- */
- public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
-
- writeIdList(beanDescriptor, 0, insertIds, msgList);
- writeIdList(beanDescriptor, 1, updateIds, msgList);
- writeIdList(beanDescriptor, 2, deleteIds, msgList);
-
- }
-
- private ArrayList readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
-
- int count = dataInput.readInt();
- if (count < 1) {
- return null;
- }
- ArrayList idList = new ArrayList(count);
- for (int i = 0; i < count; i++) {
- Object id = idBinder.readData(dataInput);
- idList.add((Serializable) id);
- }
- return idList;
- }
-
- /**
- * Write a BinaryMessage containing the descriptorId, iudType and list of Id
- * values.
- *
- * Note that a given BinaryMessage has a maximum of 100 Ids. This is due to
- * the limit of UDP packet sizes. We break up the RemoteBeanPersist into
- * potentially many smaller BinaryMessages which may be put into multiple
- * Packets.
- *
- */
- private void writeIdList(BeanDescriptor> desc, int iudType, ArrayList idList,
- BinaryMessageList msgList) throws IOException {
-
- IdBinder idBinder = desc.getIdBinder();
-
- int count = idList == null ? 0 : idList.size();
- if (count > 0) {
- int loop = 0;
- int i = 0;
- int eof = idList.size();
- do {
- ++loop;
- int endOfLoop = Math.min(eof, loop * 100);
-
- BinaryMessage m = new BinaryMessage(endOfLoop * 4 + 20);
-
- DataOutputStream os = m.getOs();
- os.writeInt(BinaryMessage.TYPE_BEANIUD);
- os.writeUTF(descriptorId);
- os.writeInt(iudType);
- os.writeInt(count);
-
- for (; i < endOfLoop; i++) {
- Serializable idValue = idList.get(i);
- idBinder.writeData(os, idValue);
- }
-
- os.flush();
- msgList.add(m);
-
- } while (i < eof);
- }
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (beanDescriptor != null) {
- sb.append(beanDescriptor.getFullName());
- } else {
- sb.append("descId:").append(descriptorId);
- }
- if (insertIds != null) {
- sb.append(" insertIds:").append(insertIds);
- }
- if (updateIds != null) {
- sb.append(" updateIds:").append(updateIds);
- }
- if (deleteIds != null) {
- sb.append(" deleteIds:").append(deleteIds);
- }
- return sb.toString();
- }
-
- public void addId(PersistRequest.Type type, Serializable id) {
- switch (type) {
- case INSERT:
- addInsertId(id);
- break;
- case UPDATE:
- addUpdateId(id);
- break;
- case DELETE:
- addDeleteId(id);
- break;
-
- default:
- break;
- }
- }
-
- private void addInsertId(Serializable id) {
- if (insertIds == null) {
- insertIds = new ArrayList();
- }
- insertIds.add(id);
- }
-
- private void addUpdateId(Serializable id) {
- if (updateIds == null) {
- updateIds = new ArrayList();
- }
- updateIds.add(id);
- }
-
- private void addDeleteId(Serializable id) {
- if (deleteIds == null) {
- deleteIds = new ArrayList();
- }
- deleteIds.add(id);
- }
-
- public BeanDescriptor> getBeanDescriptor() {
- return beanDescriptor;
- }
-
- /**
- * Return the Descriptor Id. A more compact alternative to using the
- * beanType.
- */
- public String getDescriptorId() {
- return descriptorId;
- }
-
- public List getInsertIds() {
- return insertIds;
- }
-
- public List getUpdateIds() {
- return updateIds;
- }
-
- public List getDeleteIds() {
- return deleteIds;
- }
-
- public void setBeanDescriptor(BeanDescriptor> beanDescriptor) {
- this.beanDescriptor = beanDescriptor;
- }
-
- /**
- * Notify the cache and local BeanPersistListener of this event that came
- * from another server in the cluster.
- */
- public void notifyCacheAndListener() {
-
- BeanPersistListener listener = beanDescriptor.getPersistListener();
-
- // any change invalidates the query cache
- beanDescriptor.queryCacheClear();
-
- if (insertIds != null) {
- if (listener != null) {
- // notify listener
- for (int i = 0; i < insertIds.size(); i++) {
- listener.remoteInsert(insertIds.get(i));
- }
- }
- }
- if (updateIds != null) {
- for (int i = 0; i < updateIds.size(); i++) {
- Serializable id = updateIds.get(i);
-
- // remove from cache
- beanDescriptor.cacheBeanRemove(id);
- if (listener != null) {
- // notify listener
- listener.remoteInsert(id);
- }
- }
- }
- if (deleteIds != null) {
- for (int i = 0; i < deleteIds.size(); i++) {
- Serializable id = deleteIds.get(i);
-
- // remove from cache
- beanDescriptor.cacheBeanRemove(id);
- if (listener != null) {
- // notify listener
- listener.remoteInsert(id);
- }
- }
- }
-
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.DataInput;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.avaje.ebean.event.BeanPersistListener;
+import com.avaje.ebeaninternal.api.SpiEbeanServer;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessage;
+import com.avaje.ebeaninternal.server.cluster.BinaryMessageList;
+import com.avaje.ebeaninternal.server.core.PersistRequest;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+import com.avaje.ebeaninternal.server.deploy.id.IdBinder;
+
+/**
+ * Wraps the information representing a Inserted Updated or Deleted Bean.
+ *
+ * This information is broadcast across the cluster so that remote BeanListeners
+ * are notified of the inserts updates and deletes that occured.
+ *
+ *
+ * You control it the data is broadcast and what data is broadcast by the
+ * BeanListener.getClusterData() method. It is guessed that often just the Id
+ * property or perhaps a few properties in a Map will be broadcast to reduce the
+ * size of data sent around the network.
+ *
+ * For a RemoteBeanPersist with a large number of id's note that this is
+ * broken up into many BinaryMessages each with a maximum of 100 ids. This
+ * enables the contents of a large RemoteTransactionEvent to be split up
+ * across multiple Packets.
+ *
+ */
+ public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
+
+ writeIdList(beanDescriptor, 0, insertIds, msgList);
+ writeIdList(beanDescriptor, 1, updateIds, msgList);
+ writeIdList(beanDescriptor, 2, deleteIds, msgList);
+
+ }
+
+ private ArrayList readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
+
+ int count = dataInput.readInt();
+ if (count < 1) {
+ return null;
+ }
+ ArrayList idList = new ArrayList(count);
+ for (int i = 0; i < count; i++) {
+ Object id = idBinder.readData(dataInput);
+ idList.add((Serializable) id);
+ }
+ return idList;
+ }
+
+ /**
+ * Write a BinaryMessage containing the descriptorId, iudType and list of Id
+ * values.
+ *
+ * Note that a given BinaryMessage has a maximum of 100 Ids. This is due to
+ * the limit of UDP packet sizes. We break up the RemoteBeanPersist into
+ * potentially many smaller BinaryMessages which may be put into multiple
+ * Packets.
+ *
+ */
+ private void writeIdList(BeanDescriptor> desc, int iudType, ArrayList idList,
+ BinaryMessageList msgList) throws IOException {
+
+ IdBinder idBinder = desc.getIdBinder();
+
+ int count = idList == null ? 0 : idList.size();
+ if (count > 0) {
+ int loop = 0;
+ int i = 0;
+ int eof = idList.size();
+ do {
+ ++loop;
+ int endOfLoop = Math.min(eof, loop * 100);
+
+ BinaryMessage m = new BinaryMessage(endOfLoop * 4 + 20);
+
+ DataOutputStream os = m.getOs();
+ os.writeInt(BinaryMessage.TYPE_BEANIUD);
+ os.writeUTF(descriptorId);
+ os.writeInt(iudType);
+ os.writeInt(count);
+
+ for (; i < endOfLoop; i++) {
+ Serializable idValue = idList.get(i);
+ idBinder.writeData(os, idValue);
+ }
+
+ os.flush();
+ msgList.add(m);
+
+ } while (i < eof);
+ }
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (beanDescriptor != null) {
+ sb.append(beanDescriptor.getFullName());
+ } else {
+ sb.append("descId:").append(descriptorId);
+ }
+ if (insertIds != null) {
+ sb.append(" insertIds:").append(insertIds);
+ }
+ if (updateIds != null) {
+ sb.append(" updateIds:").append(updateIds);
+ }
+ if (deleteIds != null) {
+ sb.append(" deleteIds:").append(deleteIds);
+ }
+ return sb.toString();
+ }
+
+ public void addId(PersistRequest.Type type, Serializable id) {
+ switch (type) {
+ case INSERT:
+ addInsertId(id);
+ break;
+ case UPDATE:
+ addUpdateId(id);
+ break;
+ case DELETE:
+ addDeleteId(id);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private void addInsertId(Serializable id) {
+ if (insertIds == null) {
+ insertIds = new ArrayList();
+ }
+ insertIds.add(id);
+ }
+
+ private void addUpdateId(Serializable id) {
+ if (updateIds == null) {
+ updateIds = new ArrayList();
+ }
+ updateIds.add(id);
+ }
+
+ private void addDeleteId(Serializable id) {
+ if (deleteIds == null) {
+ deleteIds = new ArrayList();
+ }
+ deleteIds.add(id);
+ }
+
+ public BeanDescriptor> getBeanDescriptor() {
+ return beanDescriptor;
+ }
+
+ /**
+ * Return the Descriptor Id. A more compact alternative to using the
+ * beanType.
+ */
+ public String getDescriptorId() {
+ return descriptorId;
+ }
+
+ public List getInsertIds() {
+ return insertIds;
+ }
+
+ public List getUpdateIds() {
+ return updateIds;
+ }
+
+ public List getDeleteIds() {
+ return deleteIds;
+ }
+
+ public void setBeanDescriptor(BeanDescriptor> beanDescriptor) {
+ this.beanDescriptor = beanDescriptor;
+ }
+
+ /**
+ * Notify the cache and local BeanPersistListener of this event that came
+ * from another server in the cluster.
+ */
+ public void notifyCacheAndListener() {
+
+ BeanPersistListener listener = beanDescriptor.getPersistListener();
+
+ // any change invalidates the query cache
+ beanDescriptor.queryCacheClear();
+
+ if (insertIds != null) {
+ if (listener != null) {
+ // notify listener
+ for (int i = 0; i < insertIds.size(); i++) {
+ listener.remoteInsert(insertIds.get(i));
+ }
+ }
+ }
+ if (updateIds != null) {
+ for (int i = 0; i < updateIds.size(); i++) {
+ Serializable id = updateIds.get(i);
+
+ // remove from cache
+ beanDescriptor.cacheBeanRemove(id);
+ if (listener != null) {
+ // notify listener
+ listener.remoteInsert(id);
+ }
+ }
+ }
+ if (deleteIds != null) {
+ for (int i = 0; i < deleteIds.size(); i++) {
+ Serializable id = deleteIds.get(i);
+
+ // remove from cache
+ beanDescriptor.cacheBeanRemove(id);
+ if (listener != null) {
+ // notify listener
+ listener.remoteInsert(id);
+ }
+ }
+ }
+
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
index f6e7bb320..1112084ed 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/DefaultPersistenceContext.java
@@ -1,210 +1,210 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import javax.persistence.Entity;
-
-import com.avaje.ebean.bean.PersistenceContext;
-import com.avaje.ebeaninternal.api.Monitor;
-
-/**
- * Default implementation of PersistenceContext.
- *
- * Ensures only one instance of a bean is used according to its type and unique
- * id.
- *
- *
- * PersistenceContext lives on a Transaction and as such is expected to only
- * have a single thread accessing it at a time. This is not expected to be used
- * concurrently.
- *
- *
- * Duplicate beans are ones having the same type and unique id value. These are
- * considered duplicates and replaced by the bean instance that was already
- * loaded into the PersistanceContext.
- *
- */
-public final class DefaultPersistenceContext implements PersistenceContext {
-
- /**
- * Map used hold caches. One cache per bean type.
- */
- private final HashMap typeCache = new HashMap();
-
- private final Monitor monitor = new Monitor();
-
- /**
- * Create a new PersistanceContext.
- */
- public DefaultPersistenceContext() {
- }
-
- /**
- * Set an object into the PersistanceContext.
- */
- public void put(Object id, Object bean) {
- synchronized (monitor) {
- getClassContext(bean.getClass()).put(id, bean);
- }
- }
-
- public Object putIfAbsent(Object id, Object bean) {
- synchronized (monitor) {
- return getClassContext(bean.getClass()).putIfAbsent(id, bean);
- }
- }
-
- /**
- * Return an object given its type and unique id.
- */
- public Object get(Class> beanType, Object id) {
- synchronized (monitor) {
- return getClassContext(beanType).get(id);
- }
- }
-
- public WithOption getWithOption(Class> beanType, Object id) {
- synchronized (monitor) {
- return getClassContext(beanType).getWithOption(id);
- }
- }
-
- /**
- * Return the number of beans of the given type in the persistence context.
- */
- public int size(Class> beanType) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- return classMap == null ? 0 : classMap.size();
- }
- }
-
- /**
- * Clear the PersistenceContext.
- */
- public void clear() {
- synchronized (monitor) {
- typeCache.clear();
- }
- }
-
- public void clear(Class> beanType) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null) {
- classMap.clear();
- }
- }
- }
-
- public void deleted(Class> beanType, Object id) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null && id != null) {
- classMap.deleted(id);
- }
- }
- }
-
- public void clear(Class> beanType, Object id) {
- synchronized (monitor) {
- ClassContext classMap = typeCache.get(beanType.getName());
- if (classMap != null && id != null) {
- classMap.remove(id);
- }
- }
- }
-
- public String toString() {
- synchronized (monitor) {
- return typeCache.toString();
- }
- }
-
- private ClassContext getClassContext(Class> beanType) {
-
- String clsName = getBeanBaseType(beanType).getName();
- ClassContext classMap = typeCache.get(clsName);
- if (classMap == null) {
- classMap = new ClassContext();
- typeCache.put(clsName, classMap);
- }
- return classMap;
- }
-
- private Class> getBeanBaseType(Class> beanType) {
- Class> parent = beanType.getSuperclass();
-
- while (parent != null && parent.isAnnotationPresent(Entity.class)) {
- beanType = parent;
- parent = parent.getSuperclass();
- }
- return beanType;
- }
-
- private static class ClassContext {
-
- private final Map
- */
- public static void end(String serverName) {
-
- TransactionMap map = local.get();
- State state = map.removeState(serverName);
- if (state != null) {
- state.end();
- }
- if (map.isEmpty()) {
- local.remove();
- }
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import com.avaje.ebeaninternal.api.SpiTransaction;
+import com.avaje.ebeaninternal.server.transaction.TransactionMap.State;
+
+/**
+ * Used by EbeanMgr to store its Transactions in a ThreadLocal. This way the
+ * transaction objects don't have to passed around.
+ */
+public final class DefaultTransactionThreadLocal {
+
+ private static ThreadLocal local = new ThreadLocal() {
+ protected synchronized TransactionMap initialValue() {
+ return new TransactionMap();
+ }
+ };
+
+ /**
+ * Not allowed.
+ */
+ private DefaultTransactionThreadLocal() {
+ }
+
+ /**
+ * Return the current TransactionState for a given serverName. This is for the
+ * local thread of course.
+ */
+ private static TransactionMap.State getState(String serverName) {
+ return local.get().getStateWithCreate(serverName);
+ }
+
+ /**
+ * Set a new Transaction for this serverName and Thread.
+ */
+ public static void set(String serverName, SpiTransaction trans) {
+ getState(serverName).set(trans);
+ }
+
+ /**
+ * A mechanism to get the transaction out of the thread local by replacing it
+ * with a 'proxy'.
+ *
+ * Used for background fetching. Replaces the current transaction with a
+ * 'dummy' transaction. The current transaction is given to the background
+ * thread so it can continue the fetch.
+ *
+ */
+ public static void replace(String serverName, SpiTransaction trans) {
+ getState(serverName).replace(trans);
+ }
+
+ /**
+ * Return the current Transaction for this serverName and Thread.
+ */
+ public static SpiTransaction get(String serverName) {
+ TransactionMap map = local.get();
+ State state = map.getState(serverName);
+ SpiTransaction t = (state == null) ? null : state.transaction;
+ if (map.isEmpty()) {
+ local.remove();
+ }
+ return t;
+ }
+
+ /**
+ * Commit the current transaction.
+ */
+ public static void commit(String serverName) {
+ TransactionMap map = local.get();
+ State state = map.removeState(serverName);
+ if (state == null) {
+ throw new IllegalStateException("No current transaction for [" + serverName + "]");
+ }
+ state.commit();
+ if (map.isEmpty()) {
+ local.remove();
+ }
+ }
+
+ /**
+ * Rollback the current transaction.
+ */
+ public static void rollback(String serverName) {
+ TransactionMap map = local.get();
+ State state = map.removeState(serverName);
+ if (state == null) {
+ throw new IllegalStateException("No current transaction for [" + serverName + "]");
+ }
+ state.rollback();
+ if (map.isEmpty()) {
+ local.remove();
+ }
+ }
+
+ /**
+ * If the transaction has not been committed then roll it back.
+ *
+ * Designed to be put in a finally block instead of a rollback() in each catch
+ * block.
+ *
+ *
+ * Ebean.beingTransaction();
+ * try {
+ * // ... perform some actions in a single transaction
+ *
+ * Ebean.commitTransaction();
+ *
+ * } finally {
+ * // ensure transaction ended. If some error occurred then rollback()
+ * Ebean.endTransaction();
+ * }
+ *
+ *
+ *
+ */
+ public static void end(String serverName) {
+
+ TransactionMap map = local.get();
+ State state = map.removeState(serverName);
+ if (state != null) {
+ state.end();
+ }
+ if (map.isEmpty()) {
+ local.remove();
+ }
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/DeleteByIdMap.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/DeleteByIdMap.java
index 7a58e12ca..d0760ad14 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/DeleteByIdMap.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/DeleteByIdMap.java
@@ -1,76 +1,76 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.io.Serializable;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.avaje.ebeaninternal.server.core.PersistRequest;
-import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
-
-/**
- * Beans deleted by Id used for updating L2 Cache.
- */
-public final class DeleteByIdMap {
-
- private final Map beanMap = new LinkedHashMap();
-
- public String toString() {
- return beanMap.toString();
- }
-
- public void notifyCache() {
- for (BeanPersistIds deleteIds : beanMap.values()) {
- BeanDescriptor> d = deleteIds.getBeanDescriptor();
- List idValues = deleteIds.getDeleteIds();
- if (idValues != null){
- d.queryCacheClear();
- for (int i = 0; i < idValues.size(); i++) {
- d.cacheBeanRemove(idValues.get(i));
- }
- }
- }
-
- }
-
- public boolean isEmpty() {
- return beanMap.isEmpty();
- }
-
- public Collection values() {
- return beanMap.values();
- }
-
- /**
- * Add a Insert Update or Delete payload.
- */
- public void add(BeanDescriptor> desc, Object id) {
-
- BeanPersistIds r = getPersistIds(desc);
- r.addId(PersistRequest.Type.DELETE, (Serializable)id);
- }
-
- /**
- * Add a List of Insert Update or Delete Id's.
- */
- public void addList(BeanDescriptor> desc, List idList) {
-
- BeanPersistIds r = getPersistIds(desc);
- for (int i = 0; i < idList.size(); i++) {
- r.addId(PersistRequest.Type.DELETE, (Serializable) idList.get(i));
- }
- }
-
- private BeanPersistIds getPersistIds(BeanDescriptor> desc) {
- String beanType = desc.getFullName();
- BeanPersistIds r = beanMap.get(beanType);
- if (r == null){
- r = new BeanPersistIds(desc);
- beanMap.put(beanType, r);
- }
- return r;
- }
-
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.avaje.ebeaninternal.server.core.PersistRequest;
+import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
+
+/**
+ * Beans deleted by Id used for updating L2 Cache.
+ */
+public final class DeleteByIdMap {
+
+ private final Map beanMap = new LinkedHashMap();
+
+ public String toString() {
+ return beanMap.toString();
+ }
+
+ public void notifyCache() {
+ for (BeanPersistIds deleteIds : beanMap.values()) {
+ BeanDescriptor> d = deleteIds.getBeanDescriptor();
+ List idValues = deleteIds.getDeleteIds();
+ if (idValues != null){
+ d.queryCacheClear();
+ for (int i = 0; i < idValues.size(); i++) {
+ d.cacheBeanRemove(idValues.get(i));
+ }
+ }
+ }
+
+ }
+
+ public boolean isEmpty() {
+ return beanMap.isEmpty();
+ }
+
+ public Collection values() {
+ return beanMap.values();
+ }
+
+ /**
+ * Add a Insert Update or Delete payload.
+ */
+ public void add(BeanDescriptor> desc, Object id) {
+
+ BeanPersistIds r = getPersistIds(desc);
+ r.addId(PersistRequest.Type.DELETE, (Serializable)id);
+ }
+
+ /**
+ * Add a List of Insert Update or Delete Id's.
+ */
+ public void addList(BeanDescriptor> desc, List idList) {
+
+ BeanPersistIds r = getPersistIds(desc);
+ for (int i = 0; i < idList.size(); i++) {
+ r.addId(PersistRequest.Type.DELETE, (Serializable) idList.get(i));
+ }
+ }
+
+ private BeanPersistIds getPersistIds(BeanDescriptor> desc) {
+ String beanType = desc.getFullName();
+ BeanPersistIds r = beanMap.get(beanType);
+ if (r == null){
+ r = new BeanPersistIds(desc);
+ beanMap.put(beanType, r);
+ }
+ return r;
+ }
+
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java
index 106a7ef5e..c8b6cf4d8 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/ExternalTransactionScopeManager.java
@@ -1,48 +1,48 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import com.avaje.ebean.config.ExternalTransactionManager;
-import com.avaje.ebeaninternal.api.SpiTransaction;
-
-/**
- * A TransactionScopeManager aware of external transaction managers.
- */
-public class ExternalTransactionScopeManager extends TransactionScopeManager {
-
- final ExternalTransactionManager externalManager;
-
- /**
- * Instantiates transaction scope manager.
- *
- * @param transactionManager the transaction manager
- */
- public ExternalTransactionScopeManager(TransactionManager transactionManager, ExternalTransactionManager externalManager) {
- super(transactionManager);
- this.externalManager = externalManager;
- }
-
- public void commit() {
- DefaultTransactionThreadLocal.commit(serverName);
- }
-
-
- public void end() {
- DefaultTransactionThreadLocal.end(serverName);
- }
-
- public SpiTransaction get() {
-
- return (SpiTransaction)externalManager.getCurrentTransaction();
- }
-
- public void replace(SpiTransaction trans) {
- DefaultTransactionThreadLocal.replace(serverName, trans);
- }
-
- public void rollback() {
- DefaultTransactionThreadLocal.rollback(serverName);
- }
-
- public void set(SpiTransaction trans) {
- DefaultTransactionThreadLocal.set(serverName, trans);
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import com.avaje.ebean.config.ExternalTransactionManager;
+import com.avaje.ebeaninternal.api.SpiTransaction;
+
+/**
+ * A TransactionScopeManager aware of external transaction managers.
+ */
+public class ExternalTransactionScopeManager extends TransactionScopeManager {
+
+ final ExternalTransactionManager externalManager;
+
+ /**
+ * Instantiates transaction scope manager.
+ *
+ * @param transactionManager the transaction manager
+ */
+ public ExternalTransactionScopeManager(TransactionManager transactionManager, ExternalTransactionManager externalManager) {
+ super(transactionManager);
+ this.externalManager = externalManager;
+ }
+
+ public void commit() {
+ DefaultTransactionThreadLocal.commit(serverName);
+ }
+
+
+ public void end() {
+ DefaultTransactionThreadLocal.end(serverName);
+ }
+
+ public SpiTransaction get() {
+
+ return (SpiTransaction)externalManager.getCurrentTransaction();
+ }
+
+ public void replace(SpiTransaction trans) {
+ DefaultTransactionThreadLocal.replace(serverName, trans);
+ }
+
+ public void rollback() {
+ DefaultTransactionThreadLocal.rollback(serverName);
+ }
+
+ public void set(SpiTransaction trans) {
+ DefaultTransactionThreadLocal.set(serverName, trans);
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransaction.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransaction.java
index 6947734ee..aa4d501bf 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransaction.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransaction.java
@@ -1,117 +1,117 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.sql.SQLException;
-
-import javax.persistence.PersistenceException;
-import javax.sql.DataSource;
-import javax.transaction.Status;
-import javax.transaction.UserTransaction;
-
-/**
- * Jta based transaction.
- */
-public class JtaTransaction extends JdbcTransaction {
-
- private UserTransaction userTransaction;
-
- private DataSource dataSource;
-
- private boolean commmitted = false;
-
- private boolean newTransaction = false;
-
-
- /**
- * Create the JtaTransaction.
- */
- public JtaTransaction(String id, boolean explicit, UserTransaction utx, DataSource ds, TransactionManager manager) {
- super(id, explicit, null, manager);
- userTransaction = utx;
- dataSource = ds;
-
- try {
- newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
- if (newTransaction) {
- userTransaction.begin();
- }
- } catch (Exception e) {
- throw new PersistenceException(e);
- }
-
- try {
- // Open JDBC Connection
- this.connection = dataSource.getConnection();
- if (connection == null) {
- throw new PersistenceException("The DataSource returned a null connection.");
- }
- if (connection.getAutoCommit()) {
- connection.setAutoCommit(false);
- }
-
- } catch (SQLException e) {
- throw new PersistenceException(e);
- }
- }
-
- /**
- * Commit the transaction.
- */
- public void commit() {
- if (commmitted) {
- throw new PersistenceException("This transaction has already been committed.");
- }
- try {
- try {
- if (newTransaction) {
- userTransaction.commit();
- }
- notifyCommit();
- } finally {
- close();
- }
- } catch (Exception e) {
- throw new PersistenceException(e);
- }
- commmitted = true;
- }
-
- public void rollback() {
- rollback(null);
- }
-
- /**
- * Rollback the transaction.
- */
- public void rollback(Throwable e) {
- if (!commmitted) {
- try {
- try {
- if (userTransaction != null) {
- if (newTransaction) {
- userTransaction.rollback();
- } else {
- userTransaction.setRollbackOnly();
- }
- }
- notifyRollback(e);
- } finally {
- closeConnection();
- }
- } catch (Exception ex) {
- throw new PersistenceException(ex);
- }
- }
-
- }
-
- /**
- * Close the underlying connection.
- */
- private void closeConnection() throws SQLException {
- if (connection != null) {
- connection.close();
- connection = null;
- }
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.sql.SQLException;
+
+import javax.persistence.PersistenceException;
+import javax.sql.DataSource;
+import javax.transaction.Status;
+import javax.transaction.UserTransaction;
+
+/**
+ * Jta based transaction.
+ */
+public class JtaTransaction extends JdbcTransaction {
+
+ private UserTransaction userTransaction;
+
+ private DataSource dataSource;
+
+ private boolean commmitted = false;
+
+ private boolean newTransaction = false;
+
+
+ /**
+ * Create the JtaTransaction.
+ */
+ public JtaTransaction(String id, boolean explicit, UserTransaction utx, DataSource ds, TransactionManager manager) {
+ super(id, explicit, null, manager);
+ userTransaction = utx;
+ dataSource = ds;
+
+ try {
+ newTransaction = userTransaction.getStatus() == Status.STATUS_NO_TRANSACTION;
+ if (newTransaction) {
+ userTransaction.begin();
+ }
+ } catch (Exception e) {
+ throw new PersistenceException(e);
+ }
+
+ try {
+ // Open JDBC Connection
+ this.connection = dataSource.getConnection();
+ if (connection == null) {
+ throw new PersistenceException("The DataSource returned a null connection.");
+ }
+ if (connection.getAutoCommit()) {
+ connection.setAutoCommit(false);
+ }
+
+ } catch (SQLException e) {
+ throw new PersistenceException(e);
+ }
+ }
+
+ /**
+ * Commit the transaction.
+ */
+ public void commit() {
+ if (commmitted) {
+ throw new PersistenceException("This transaction has already been committed.");
+ }
+ try {
+ try {
+ if (newTransaction) {
+ userTransaction.commit();
+ }
+ notifyCommit();
+ } finally {
+ close();
+ }
+ } catch (Exception e) {
+ throw new PersistenceException(e);
+ }
+ commmitted = true;
+ }
+
+ public void rollback() {
+ rollback(null);
+ }
+
+ /**
+ * Rollback the transaction.
+ */
+ public void rollback(Throwable e) {
+ if (!commmitted) {
+ try {
+ try {
+ if (userTransaction != null) {
+ if (newTransaction) {
+ userTransaction.rollback();
+ } else {
+ userTransaction.setRollbackOnly();
+ }
+ }
+ notifyRollback(e);
+ } finally {
+ closeConnection();
+ }
+ } catch (Exception ex) {
+ throw new PersistenceException(ex);
+ }
+ }
+
+ }
+
+ /**
+ * Close the underlying connection.
+ */
+ private void closeConnection() throws SQLException {
+ if (connection != null) {
+ connection.close();
+ connection = null;
+ }
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransactionManager.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransactionManager.java
index a6f3d6a32..6a6f3d4ef 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransactionManager.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/JtaTransactionManager.java
@@ -1,229 +1,229 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-import javax.persistence.PersistenceException;
-import javax.sql.DataSource;
-import javax.transaction.HeuristicMixedException;
-import javax.transaction.HeuristicRollbackException;
-import javax.transaction.NotSupportedException;
-import javax.transaction.RollbackException;
-import javax.transaction.Status;
-import javax.transaction.Synchronization;
-import javax.transaction.SystemException;
-import javax.transaction.TransactionSynchronizationRegistry;
-import javax.transaction.UserTransaction;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.avaje.ebean.config.ExternalTransactionManager;
-import com.avaje.ebeaninternal.api.SpiTransaction;
-
-/**
- * Hook into external JTA transaction manager.
- *
- * @author rbygrave
- */
-public class JtaTransactionManager implements ExternalTransactionManager {
-
- private static final Logger logger = LoggerFactory.getLogger(JtaTransactionManager.class);
-
- private static final String EBEAN_TXN_RESOURCE = "EBEAN_TXN_RESOURCE";
-
- /**
- * The data source.
- */
- private DataSource dataSource;
-
- /**
- * The Ebean transaction manager.
- */
- private TransactionManager transactionManager;
-
- /**
- * The EbeanServer name.
- */
- private String serverName;
-
- /**
- * Instantiates a new spring aware transaction scope manager.
- */
- public JtaTransactionManager() {
- }
-
- /**
- * Initialise this with the Ebean internal transaction manager.
- */
- public void setTransactionManager(Object txnMgr) {
-
- // RB: At this stage not exposing TransactionManager to
- // the public API and hence the Object type and casting here
-
- this.transactionManager = (TransactionManager) txnMgr;
- this.dataSource = transactionManager.getDataSource();
- this.serverName = transactionManager.getServerName();
- }
-
- private TransactionSynchronizationRegistry getSyncRegistry() {
- try {
- InitialContext ctx = new InitialContext();
- return (TransactionSynchronizationRegistry)ctx.lookup("java:comp/TransactionSynchronizationRegistry");
- } catch (NamingException e){
- throw new PersistenceException(e);
- }
- }
-
- private UserTransaction getUserTransaction() {
- try {
- InitialContext ctx = new InitialContext();
- return (UserTransaction) ctx.lookup("java:comp/UserTransaction");
- } catch (NamingException e){
- // assuming CMT
- return new DummyUserTransaction();
- }
- }
-
- /**
- * Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction.
- *
- * Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
- *
- */
- public Object getCurrentTransaction() {
-
- TransactionSynchronizationRegistry syncRegistry = getSyncRegistry();
-
- SpiTransaction t = (SpiTransaction)syncRegistry.getResource(EBEAN_TXN_RESOURCE);
- if (t != null){
- // we have already seen this transaction
- return t;
- }
-
- // check current Ebean transaction
- SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName);
- if (currentEbeanTransaction != null){
- // NOT expecting this so log WARNING
- String msg = "JTA Transaction - no current txn BUT using current Ebean one "+currentEbeanTransaction.getId();
- logger.warn(msg);
- return currentEbeanTransaction;
- }
-
- UserTransaction ut = getUserTransaction();
- if (ut == null){
- // no current JTA transaction
- if (logger.isDebugEnabled()){
- logger.debug("JTA Transaction - no current txn");
- }
- return null;
- }
-
- // This is a transaction that Ebean has not seen before.
-
- // "wrap" it in a Ebean specific JtaTransaction
- String txnId = String.valueOf(System.currentTimeMillis());
- JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager);
-
- // create and register transaction listener
- JtaTxnListener txnListener = createJtaTxnListener(newTrans);
-
- syncRegistry.putResource(EBEAN_TXN_RESOURCE, newTrans);
- syncRegistry.registerInterposedSynchronization(txnListener);
-
- // also put in Ebean ThreadLocal
- DefaultTransactionThreadLocal.set(serverName, newTrans);
- return newTrans;
- }
-
-
- /**
- * Create a listener to register with JTA to enable Ebean to be
- * notified when transactions commit and rollback.
- *
- * This is used by Ebean to notify it's appropriate listeners and maintain it's server
- * cache etc.
- *
- */
- private JtaTxnListener createJtaTxnListener(SpiTransaction t) {
- return new JtaTxnListener(transactionManager, t);
- }
-
- private static class DummyUserTransaction implements UserTransaction {
-
- public void begin() throws NotSupportedException, SystemException {
- }
-
- public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
- SecurityException, IllegalStateException, SystemException {
- }
-
- public int getStatus() throws SystemException {
- return 0;
- }
-
- public void rollback() throws IllegalStateException, SecurityException, SystemException {
- }
-
- public void setRollbackOnly() throws IllegalStateException, SystemException {
- }
-
- public void setTransactionTimeout(int seconds) throws SystemException {
- }
- }
-
- /**
- * A JTA Transaction Synchronization that we register to get notified when a
- * managed transaction has been committed or rolled back.
- *
- * When Ebean is notified (of the commit/rollback) it can then manage its
- * cache, notify BeanPersistListeners etc.
- *
- */
- private static class JtaTxnListener implements Synchronization {
-
- private final TransactionManager transactionManager;
-
- private final SpiTransaction transaction;
-
- private final String serverName;
-
- private JtaTxnListener(TransactionManager transactionManager, SpiTransaction t){
- this.transactionManager = transactionManager;
- this.transaction = t;
- this.serverName = transactionManager.getServerName();
- }
-
- public void beforeCompletion() {
- // Future note: for JPA2 locking we will
- // have beforeCommit events to fire
- }
-
- public void afterCompletion(int status) {
-
- switch (status) {
- case Status.STATUS_COMMITTED:
- if (logger.isDebugEnabled()){
- logger.debug("Jta Txn ["+transaction.getId()+"] committed");
- }
- transactionManager.notifyOfCommit(transaction);
- // Remove this transaction object as it is completed
- DefaultTransactionThreadLocal.replace(serverName, null);
- break;
-
- case Status.STATUS_ROLLEDBACK:
- if (logger.isDebugEnabled()){
- logger.debug("Jta Txn ["+transaction.getId()+"] rollback");
- }
- transactionManager.notifyOfRollback(transaction, null);
- // Remove this transaction object as it is completed
- DefaultTransactionThreadLocal.replace(serverName, null);
- break;
-
- default:
- logger.debug("Jta Txn ["+transaction.getId()+"] status:"+status);
- }
-
- }
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.persistence.PersistenceException;
+import javax.sql.DataSource;
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.TransactionSynchronizationRegistry;
+import javax.transaction.UserTransaction;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.avaje.ebean.config.ExternalTransactionManager;
+import com.avaje.ebeaninternal.api.SpiTransaction;
+
+/**
+ * Hook into external JTA transaction manager.
+ *
+ * @author rbygrave
+ */
+public class JtaTransactionManager implements ExternalTransactionManager {
+
+ private static final Logger logger = LoggerFactory.getLogger(JtaTransactionManager.class);
+
+ private static final String EBEAN_TXN_RESOURCE = "EBEAN_TXN_RESOURCE";
+
+ /**
+ * The data source.
+ */
+ private DataSource dataSource;
+
+ /**
+ * The Ebean transaction manager.
+ */
+ private TransactionManager transactionManager;
+
+ /**
+ * The EbeanServer name.
+ */
+ private String serverName;
+
+ /**
+ * Instantiates a new spring aware transaction scope manager.
+ */
+ public JtaTransactionManager() {
+ }
+
+ /**
+ * Initialise this with the Ebean internal transaction manager.
+ */
+ public void setTransactionManager(Object txnMgr) {
+
+ // RB: At this stage not exposing TransactionManager to
+ // the public API and hence the Object type and casting here
+
+ this.transactionManager = (TransactionManager) txnMgr;
+ this.dataSource = transactionManager.getDataSource();
+ this.serverName = transactionManager.getServerName();
+ }
+
+ private TransactionSynchronizationRegistry getSyncRegistry() {
+ try {
+ InitialContext ctx = new InitialContext();
+ return (TransactionSynchronizationRegistry)ctx.lookup("java:comp/TransactionSynchronizationRegistry");
+ } catch (NamingException e){
+ throw new PersistenceException(e);
+ }
+ }
+
+ private UserTransaction getUserTransaction() {
+ try {
+ InitialContext ctx = new InitialContext();
+ return (UserTransaction) ctx.lookup("java:comp/UserTransaction");
+ } catch (NamingException e){
+ // assuming CMT
+ return new DummyUserTransaction();
+ }
+ }
+
+ /**
+ * Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction.
+ *
+ * Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
+ *
+ */
+ public Object getCurrentTransaction() {
+
+ TransactionSynchronizationRegistry syncRegistry = getSyncRegistry();
+
+ SpiTransaction t = (SpiTransaction)syncRegistry.getResource(EBEAN_TXN_RESOURCE);
+ if (t != null){
+ // we have already seen this transaction
+ return t;
+ }
+
+ // check current Ebean transaction
+ SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName);
+ if (currentEbeanTransaction != null){
+ // NOT expecting this so log WARNING
+ String msg = "JTA Transaction - no current txn BUT using current Ebean one "+currentEbeanTransaction.getId();
+ logger.warn(msg);
+ return currentEbeanTransaction;
+ }
+
+ UserTransaction ut = getUserTransaction();
+ if (ut == null){
+ // no current JTA transaction
+ if (logger.isDebugEnabled()){
+ logger.debug("JTA Transaction - no current txn");
+ }
+ return null;
+ }
+
+ // This is a transaction that Ebean has not seen before.
+
+ // "wrap" it in a Ebean specific JtaTransaction
+ String txnId = String.valueOf(System.currentTimeMillis());
+ JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager);
+
+ // create and register transaction listener
+ JtaTxnListener txnListener = createJtaTxnListener(newTrans);
+
+ syncRegistry.putResource(EBEAN_TXN_RESOURCE, newTrans);
+ syncRegistry.registerInterposedSynchronization(txnListener);
+
+ // also put in Ebean ThreadLocal
+ DefaultTransactionThreadLocal.set(serverName, newTrans);
+ return newTrans;
+ }
+
+
+ /**
+ * Create a listener to register with JTA to enable Ebean to be
+ * notified when transactions commit and rollback.
+ *
+ * This is used by Ebean to notify it's appropriate listeners and maintain it's server
+ * cache etc.
+ *
+ */
+ private JtaTxnListener createJtaTxnListener(SpiTransaction t) {
+ return new JtaTxnListener(transactionManager, t);
+ }
+
+ private static class DummyUserTransaction implements UserTransaction {
+
+ public void begin() throws NotSupportedException, SystemException {
+ }
+
+ public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+ SecurityException, IllegalStateException, SystemException {
+ }
+
+ public int getStatus() throws SystemException {
+ return 0;
+ }
+
+ public void rollback() throws IllegalStateException, SecurityException, SystemException {
+ }
+
+ public void setRollbackOnly() throws IllegalStateException, SystemException {
+ }
+
+ public void setTransactionTimeout(int seconds) throws SystemException {
+ }
+ }
+
+ /**
+ * A JTA Transaction Synchronization that we register to get notified when a
+ * managed transaction has been committed or rolled back.
+ *
+ * When Ebean is notified (of the commit/rollback) it can then manage its
+ * cache, notify BeanPersistListeners etc.
+ *
+ */
+ private static class JtaTxnListener implements Synchronization {
+
+ private final TransactionManager transactionManager;
+
+ private final SpiTransaction transaction;
+
+ private final String serverName;
+
+ private JtaTxnListener(TransactionManager transactionManager, SpiTransaction t){
+ this.transactionManager = transactionManager;
+ this.transaction = t;
+ this.serverName = transactionManager.getServerName();
+ }
+
+ public void beforeCompletion() {
+ // Future note: for JPA2 locking we will
+ // have beforeCommit events to fire
+ }
+
+ public void afterCompletion(int status) {
+
+ switch (status) {
+ case Status.STATUS_COMMITTED:
+ if (logger.isDebugEnabled()){
+ logger.debug("Jta Txn ["+transaction.getId()+"] committed");
+ }
+ transactionManager.notifyOfCommit(transaction);
+ // Remove this transaction object as it is completed
+ DefaultTransactionThreadLocal.replace(serverName, null);
+ break;
+
+ case Status.STATUS_ROLLEDBACK:
+ if (logger.isDebugEnabled()){
+ logger.debug("Jta Txn ["+transaction.getId()+"] rollback");
+ }
+ transactionManager.notifyOfRollback(transaction, null);
+ // Remove this transaction object as it is completed
+ DefaultTransactionThreadLocal.replace(serverName, null);
+ break;
+
+ default:
+ logger.debug("Jta Txn ["+transaction.getId()+"] status:"+status);
+ }
+
+ }
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/PostCommitProcessing.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/PostCommitProcessing.java
index 2243ca4ef..da0e23979 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/PostCommitProcessing.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/PostCommitProcessing.java
@@ -1,163 +1,163 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import com.avaje.ebeaninternal.api.TransactionEvent;
-import com.avaje.ebeaninternal.api.TransactionEventBeans;
-import com.avaje.ebeaninternal.api.TransactionEventTable;
-import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
-import com.avaje.ebeaninternal.server.cluster.ClusterManager;
-import com.avaje.ebeaninternal.server.core.PersistRequestBean;
-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.
- *
- * This includes Cluster notification, and BeanPersistListeners.
- *
- */
-public final class PostCommitProcessing {
-
- private static final Logger logger = LoggerFactory.getLogger(PostCommitProcessing.class);
-
- private final ClusterManager clusterManager;
-
- private final TransactionEvent event;
-
- private final String serverName;
-
- private final TransactionManager manager;
-
- private final List> persistBeanRequests;
-
- private final BeanPersistIdMap beanPersistIdMap;
-
- private final RemoteTransactionEvent remoteTransactionEvent;
-
- private final DeleteByIdMap deleteByIdMap;
-
- /**
- * Create for a TransactionManager and event.
- */
- public PostCommitProcessing(ClusterManager clusterManager, TransactionManager manager, TransactionEvent event) {
-
- this.clusterManager = clusterManager;
- this.manager = manager;
- this.serverName = manager.getServerName();
- this.event = event;
- this.deleteByIdMap = event.getDeleteByIdMap();
- this.persistBeanRequests = createPersistBeanRequests();
- this.beanPersistIdMap = createBeanPersistIdMap();
- this.remoteTransactionEvent = createRemoteTransactionEvent();
- }
-
- public void notifyLocalCacheIndex() {
-
- // notify cache with bulk insert/update/delete statements
- processTableEvents(event.getEventTables());
-
- // notify cache with bean changes
- event.notifyCache();
- }
-
- /**
- * Table events are where SQL or external tools are used. In this case the
- * cache is notified based on the table name (rather than bean type).
- */
- private void processTableEvents(TransactionEventTable tableEvents) {
-
- if (tableEvents != null && !tableEvents.isEmpty()) {
- // notify cache with table based changes
- BeanDescriptorManager dm = manager.getBeanDescriptorManager();
- for (TableIUD tableIUD : tableEvents.values()) {
- dm.cacheNotify(tableIUD);
- }
- }
- }
-
- public void notifyCluster() {
- if (remoteTransactionEvent != null && !remoteTransactionEvent.isEmpty()) {
- // send the interesting events to the cluster
- if (logger.isDebugEnabled()) {
- logger.debug("Cluster Send: {}", remoteTransactionEvent);
- }
-
- clusterManager.broadcast(remoteTransactionEvent);
- }
- }
-
- public Runnable notifyPersistListeners() {
- return new Runnable() {
- public void run() {
- localPersistListenersNotify();
- }
- };
- }
-
- private void localPersistListenersNotify() {
- if (persistBeanRequests != null) {
- for (int i = 0; i < persistBeanRequests.size(); i++) {
- persistBeanRequests.get(i).notifyLocalPersistListener();
- }
- }
- TransactionEventTable eventTables = event.getEventTables();
- if (eventTables != null && !eventTables.isEmpty()) {
- BulkEventListenerMap map = manager.getBulkEventListenerMap();
- for (TableIUD tableIUD : eventTables.values()) {
- map.process(tableIUD);
- }
- }
- }
-
- private List> createPersistBeanRequests() {
- TransactionEventBeans eventBeans = event.getEventBeans();
- if (eventBeans != null) {
- return eventBeans.getRequests();
- }
- return null;
- }
-
- private BeanPersistIdMap createBeanPersistIdMap() {
-
- if (persistBeanRequests == null) {
- return null;
- }
-
- BeanPersistIdMap m = new BeanPersistIdMap();
- for (int i = 0; i < persistBeanRequests.size(); i++) {
- persistBeanRequests.get(i).addToPersistMap(m);
- }
- return m;
- }
-
- private RemoteTransactionEvent createRemoteTransactionEvent() {
-
- if (!clusterManager.isClustering()) {
- return null;
- }
-
- RemoteTransactionEvent remoteTransactionEvent = new RemoteTransactionEvent(serverName);
-
- if (beanPersistIdMap != null) {
- for (BeanPersistIds beanPersist : beanPersistIdMap.values()) {
- remoteTransactionEvent.addBeanPersistIds(beanPersist);
- }
- }
-
- if (deleteByIdMap != null) {
- remoteTransactionEvent.setDeleteByIdMap(deleteByIdMap);
- }
-
- TransactionEventTable eventTables = event.getEventTables();
- if (eventTables != null && !eventTables.isEmpty()) {
- for (TableIUD tableIUD : eventTables.values()) {
- remoteTransactionEvent.addTableIUD(tableIUD);
- }
- }
-
- return remoteTransactionEvent;
- }
-
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import com.avaje.ebeaninternal.api.TransactionEvent;
+import com.avaje.ebeaninternal.api.TransactionEventBeans;
+import com.avaje.ebeaninternal.api.TransactionEventTable;
+import com.avaje.ebeaninternal.api.TransactionEventTable.TableIUD;
+import com.avaje.ebeaninternal.server.cluster.ClusterManager;
+import com.avaje.ebeaninternal.server.core.PersistRequestBean;
+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.
+ *
+ * This includes Cluster notification, and BeanPersistListeners.
+ *
+ */
+public final class PostCommitProcessing {
+
+ private static final Logger logger = LoggerFactory.getLogger(PostCommitProcessing.class);
+
+ private final ClusterManager clusterManager;
+
+ private final TransactionEvent event;
+
+ private final String serverName;
+
+ private final TransactionManager manager;
+
+ private final List> persistBeanRequests;
+
+ private final BeanPersistIdMap beanPersistIdMap;
+
+ private final RemoteTransactionEvent remoteTransactionEvent;
+
+ private final DeleteByIdMap deleteByIdMap;
+
+ /**
+ * Create for a TransactionManager and event.
+ */
+ public PostCommitProcessing(ClusterManager clusterManager, TransactionManager manager, TransactionEvent event) {
+
+ this.clusterManager = clusterManager;
+ this.manager = manager;
+ this.serverName = manager.getServerName();
+ this.event = event;
+ this.deleteByIdMap = event.getDeleteByIdMap();
+ this.persistBeanRequests = createPersistBeanRequests();
+ this.beanPersistIdMap = createBeanPersistIdMap();
+ this.remoteTransactionEvent = createRemoteTransactionEvent();
+ }
+
+ public void notifyLocalCacheIndex() {
+
+ // notify cache with bulk insert/update/delete statements
+ processTableEvents(event.getEventTables());
+
+ // notify cache with bean changes
+ event.notifyCache();
+ }
+
+ /**
+ * Table events are where SQL or external tools are used. In this case the
+ * cache is notified based on the table name (rather than bean type).
+ */
+ private void processTableEvents(TransactionEventTable tableEvents) {
+
+ if (tableEvents != null && !tableEvents.isEmpty()) {
+ // notify cache with table based changes
+ BeanDescriptorManager dm = manager.getBeanDescriptorManager();
+ for (TableIUD tableIUD : tableEvents.values()) {
+ dm.cacheNotify(tableIUD);
+ }
+ }
+ }
+
+ public void notifyCluster() {
+ if (remoteTransactionEvent != null && !remoteTransactionEvent.isEmpty()) {
+ // send the interesting events to the cluster
+ if (logger.isDebugEnabled()) {
+ logger.debug("Cluster Send: {}", remoteTransactionEvent);
+ }
+
+ clusterManager.broadcast(remoteTransactionEvent);
+ }
+ }
+
+ public Runnable notifyPersistListeners() {
+ return new Runnable() {
+ public void run() {
+ localPersistListenersNotify();
+ }
+ };
+ }
+
+ private void localPersistListenersNotify() {
+ if (persistBeanRequests != null) {
+ for (int i = 0; i < persistBeanRequests.size(); i++) {
+ persistBeanRequests.get(i).notifyLocalPersistListener();
+ }
+ }
+ TransactionEventTable eventTables = event.getEventTables();
+ if (eventTables != null && !eventTables.isEmpty()) {
+ BulkEventListenerMap map = manager.getBulkEventListenerMap();
+ for (TableIUD tableIUD : eventTables.values()) {
+ map.process(tableIUD);
+ }
+ }
+ }
+
+ private List> createPersistBeanRequests() {
+ TransactionEventBeans eventBeans = event.getEventBeans();
+ if (eventBeans != null) {
+ return eventBeans.getRequests();
+ }
+ return null;
+ }
+
+ private BeanPersistIdMap createBeanPersistIdMap() {
+
+ if (persistBeanRequests == null) {
+ return null;
+ }
+
+ BeanPersistIdMap m = new BeanPersistIdMap();
+ for (int i = 0; i < persistBeanRequests.size(); i++) {
+ persistBeanRequests.get(i).addToPersistMap(m);
+ }
+ return m;
+ }
+
+ private RemoteTransactionEvent createRemoteTransactionEvent() {
+
+ if (!clusterManager.isClustering()) {
+ return null;
+ }
+
+ RemoteTransactionEvent remoteTransactionEvent = new RemoteTransactionEvent(serverName);
+
+ if (beanPersistIdMap != null) {
+ for (BeanPersistIds beanPersist : beanPersistIdMap.values()) {
+ remoteTransactionEvent.addBeanPersistIds(beanPersist);
+ }
+ }
+
+ if (deleteByIdMap != null) {
+ remoteTransactionEvent.setDeleteByIdMap(deleteByIdMap);
+ }
+
+ TransactionEventTable eventTables = event.getEventTables();
+ if (eventTables != null && !eventTables.isEmpty()) {
+ for (TableIUD tableIUD : eventTables.values()) {
+ remoteTransactionEvent.addTableIUD(tableIUD);
+ }
+ }
+
+ return remoteTransactionEvent;
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/RemoteTransactionEvent.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/RemoteTransactionEvent.java
index 9618bbac5..eb7f62d57 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/RemoteTransactionEvent.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/RemoteTransactionEvent.java
@@ -1,141 +1,141 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-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 beanPersistList = new ArrayList();
-
- private List tableList;
-
- private List beanDeltaLists;
-
- private BeanDeltaMap beanDeltaMap;
-
- private DeleteByIdMap deleteByIdMap;
-
- private String serverName;
-
- private transient SpiEbeanServer server;
-
- public RemoteTransactionEvent(String serverName) {
- this.serverName = serverName;
- }
-
- public RemoteTransactionEvent(SpiEbeanServer server) {
- this.server = server;
- }
-
- public void run() {
- server.remoteTransactionEvent(this);
- }
-
- public String toString() {
- StringBuilder sb = new StringBuilder();
- if (beanDeltaMap != null){
- sb.append(beanDeltaMap);
- }
- sb.append(beanPersistList);
- if (tableList != null){
- sb.append(tableList);
- }
- return sb.toString();
- }
-
- public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
-
- if (tableList != null){
- for (int i = 0; i < tableList.size(); i++) {
- tableList.get(i).writeBinaryMessage(msgList);
- }
- }
-
- if (deleteByIdMap != null){
- for (BeanPersistIds deleteIds : deleteByIdMap.values()) {
- deleteIds.writeBinaryMessage(msgList);
- }
- }
-
- if (beanPersistList != null){
- for (int i = 0; i < beanPersistList.size(); i++) {
- beanPersistList.get(i).writeBinaryMessage(msgList);
- }
- }
-
- if (beanDeltaLists != null){
- for (int i = 0; i < beanDeltaLists.size(); i++) {
- beanDeltaLists.get(i).writeBinaryMessage(msgList);
- }
- }
- }
-
- public boolean isEmpty() {
- return beanPersistList.isEmpty() && (tableList == null || tableList.isEmpty());
- }
-
- public void addBeanPersistIds(BeanPersistIds beanPersist){
- beanPersistList.add(beanPersist);
- }
-
- public void addTableIUD(TableIUD tableIud){
- if (tableList == null){
- tableList = new ArrayList(4);
- }
- tableList.add(tableIud);
- }
-
- public void addBeanDeltaList(BeanDeltaList deltaList){
- if (beanDeltaLists == null){
- beanDeltaLists = new ArrayList();
- }
- beanDeltaLists.add(deltaList);
- }
-
- public void addBeanDelta(BeanDelta beanDelta){
- if (beanDeltaMap == null){
- beanDeltaMap = new BeanDeltaMap();
- }
- beanDeltaMap.addBeanDelta(beanDelta);
- }
-
- public String getServerName() {
- return serverName;
- }
-
- public SpiEbeanServer getServer() {
- return server;
- }
-
- public void setServer(SpiEbeanServer server) {
- this.server = server;
- }
-
- public DeleteByIdMap getDeleteByIdMap() {
- return deleteByIdMap;
- }
-
- public void setDeleteByIdMap(DeleteByIdMap deleteByIdMap) {
- this.deleteByIdMap = deleteByIdMap;
- }
-
- public List getTableIUDList() {
- return tableList;
- }
-
- public List getBeanPersistList() {
- return beanPersistList;
- }
-
- public List getBeanDeltaLists() {
- if (beanDeltaMap != null){
- beanDeltaLists.addAll(beanDeltaMap.deltaLists());
- }
- return beanDeltaLists;
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+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 beanPersistList = new ArrayList();
+
+ private List tableList;
+
+ private List beanDeltaLists;
+
+ private BeanDeltaMap beanDeltaMap;
+
+ private DeleteByIdMap deleteByIdMap;
+
+ private String serverName;
+
+ private transient SpiEbeanServer server;
+
+ public RemoteTransactionEvent(String serverName) {
+ this.serverName = serverName;
+ }
+
+ public RemoteTransactionEvent(SpiEbeanServer server) {
+ this.server = server;
+ }
+
+ public void run() {
+ server.remoteTransactionEvent(this);
+ }
+
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ if (beanDeltaMap != null){
+ sb.append(beanDeltaMap);
+ }
+ sb.append(beanPersistList);
+ if (tableList != null){
+ sb.append(tableList);
+ }
+ return sb.toString();
+ }
+
+ public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
+
+ if (tableList != null){
+ for (int i = 0; i < tableList.size(); i++) {
+ tableList.get(i).writeBinaryMessage(msgList);
+ }
+ }
+
+ if (deleteByIdMap != null){
+ for (BeanPersistIds deleteIds : deleteByIdMap.values()) {
+ deleteIds.writeBinaryMessage(msgList);
+ }
+ }
+
+ if (beanPersistList != null){
+ for (int i = 0; i < beanPersistList.size(); i++) {
+ beanPersistList.get(i).writeBinaryMessage(msgList);
+ }
+ }
+
+ if (beanDeltaLists != null){
+ for (int i = 0; i < beanDeltaLists.size(); i++) {
+ beanDeltaLists.get(i).writeBinaryMessage(msgList);
+ }
+ }
+ }
+
+ public boolean isEmpty() {
+ return beanPersistList.isEmpty() && (tableList == null || tableList.isEmpty());
+ }
+
+ public void addBeanPersistIds(BeanPersistIds beanPersist){
+ beanPersistList.add(beanPersist);
+ }
+
+ public void addTableIUD(TableIUD tableIud){
+ if (tableList == null){
+ tableList = new ArrayList(4);
+ }
+ tableList.add(tableIud);
+ }
+
+ public void addBeanDeltaList(BeanDeltaList deltaList){
+ if (beanDeltaLists == null){
+ beanDeltaLists = new ArrayList();
+ }
+ beanDeltaLists.add(deltaList);
+ }
+
+ public void addBeanDelta(BeanDelta beanDelta){
+ if (beanDeltaMap == null){
+ beanDeltaMap = new BeanDeltaMap();
+ }
+ beanDeltaMap.addBeanDelta(beanDelta);
+ }
+
+ public String getServerName() {
+ return serverName;
+ }
+
+ public SpiEbeanServer getServer() {
+ return server;
+ }
+
+ public void setServer(SpiEbeanServer server) {
+ this.server = server;
+ }
+
+ public DeleteByIdMap getDeleteByIdMap() {
+ return deleteByIdMap;
+ }
+
+ public void setDeleteByIdMap(DeleteByIdMap deleteByIdMap) {
+ this.deleteByIdMap = deleteByIdMap;
+ }
+
+ public List getTableIUDList() {
+ return tableList;
+ }
+
+ public List getBeanPersistList() {
+ return beanPersistList;
+ }
+
+ public List getBeanDeltaLists() {
+ if (beanDeltaMap != null){
+ beanDeltaLists.addAll(beanDeltaMap.deltaLists());
+ }
+ return beanDeltaLists;
+ }
+}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionMap.java b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionMap.java
index 053c14162..e3cc71f83 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionMap.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/transaction/TransactionMap.java
@@ -1,118 +1,118 @@
-package com.avaje.ebeaninternal.server.transaction;
-
-import java.util.HashMap;
-
-import javax.persistence.PersistenceException;
-
-import com.avaje.ebeaninternal.api.SpiTransaction;
-
-
-/**
- * Current transactions mapped by server name.
- */
-public class TransactionMap {
-
- /**
- * Map of State by serverName.
- */
- private HashMap map = new HashMap();
-
- public String toString() {
- return map.toString();
- }
-
- public boolean isEmpty() {
- return map.isEmpty();
- }
-
- /**
- * Return the State for a given serverName.
- */
- public State getState(String serverName) {
-
- return map.get(serverName);
- }
-
- /**
- * Return the State for a given serverName.
- */
- public State getStateWithCreate(String serverName) {
-
- State state = map.get(serverName);
- if (state == null){
- state = new State();
- map.put(serverName, state);
- }
- return state;
- }
-
- /**
- * Remove and return the State for a given serverName.
- */
- public State removeState(String serverName) {
- return map.remove(serverName);
- }
-
- /**
- * The transaction and whether it is active.
- */
- public static class State {
-
- SpiTransaction transaction;
-
- public String toString() {
- return "txn["+transaction+"]";
- }
-
- public SpiTransaction get() {
- return transaction;
- }
-
- /**
- * Set the transaction. This will now be the current transaction.
- */
- public void set(SpiTransaction trans) {
-
- if (transaction != null && transaction.isActive()){
- String m = "The existing transaction is still active?";
- throw new PersistenceException(m);
- }
- transaction = trans;
- }
-
-
- /**
- * Commit the transaction.
- */
- public void commit() {
- transaction.commit();
- transaction = null;
- }
-
- /**
- * Rollback the transaction.
- */
- public void rollback() {
- transaction.rollback();
- transaction = null;
- }
-
- /**
- * End the transaction.
- */
- public void end() {
- if (transaction != null){
- transaction.end();
- transaction = null;
- }
- }
-
- /**
- * Used to replace transaction with a proxy.
- */
- public void replace(SpiTransaction trans) {
- transaction = trans;
- }
-
- }
-}
+package com.avaje.ebeaninternal.server.transaction;
+
+import java.util.HashMap;
+
+import javax.persistence.PersistenceException;
+
+import com.avaje.ebeaninternal.api.SpiTransaction;
+
+
+/**
+ * Current transactions mapped by server name.
+ */
+public class TransactionMap {
+
+ /**
+ * Map of State by serverName.
+ */
+ private HashMap map = new HashMap();
+
+ public String toString() {
+ return map.toString();
+ }
+
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ /**
+ * Return the State for a given serverName.
+ */
+ public State getState(String serverName) {
+
+ return map.get(serverName);
+ }
+
+ /**
+ * Return the State for a given serverName.
+ */
+ public State getStateWithCreate(String serverName) {
+
+ State state = map.get(serverName);
+ if (state == null){
+ state = new State();
+ map.put(serverName, state);
+ }
+ return state;
+ }
+
+ /**
+ * Remove and return the State for a given serverName.
+ */
+ public State removeState(String serverName) {
+ return map.remove(serverName);
+ }
+
+ /**
+ * The transaction and whether it is active.
+ */
+ public static class State {
+
+ SpiTransaction transaction;
+
+ public String toString() {
+ return "txn["+transaction+"]";
+ }
+
+ public SpiTransaction get() {
+ return transaction;
+ }
+
+ /**
+ * Set the transaction. This will now be the current transaction.
+ */
+ public void set(SpiTransaction trans) {
+
+ if (transaction != null && transaction.isActive()){
+ String m = "The existing transaction is still active?";
+ throw new PersistenceException(m);
+ }
+ transaction = trans;
+ }
+
+
+ /**
+ * Commit the transaction.
+ */
+ public void commit() {
+ transaction.commit();
+ transaction = null;
+ }
+
+ /**
+ * Rollback the transaction.
+ */
+ public void rollback() {
+ transaction.rollback();
+ transaction = null;
+ }
+
+ /**
+ * End the transaction.
+ */
+ public void end() {
+ if (transaction != null){
+ transaction.end();
+ transaction = null;
+ }
+ }
+
+ /**
+ * Used to replace transaction with a proxy.
+ */
+ public void replace(SpiTransaction trans) {
+ transaction = trans;
+ }
+
+ }
+}