mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
No effective change - change newline char
This commit is contained in:
@@ -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<BeanDeltaProperty> 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<BeanDeltaProperty>();
|
||||
}
|
||||
|
||||
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<BeanDeltaProperty> 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<BeanDeltaProperty>();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<BeanDelta> deltaBeans = new ArrayList<BeanDelta>();
|
||||
|
||||
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<BeanDelta> 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<BeanDelta> deltaBeans = new ArrayList<BeanDelta>();
|
||||
|
||||
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<BeanDelta> getDeltaBeans() {
|
||||
return deltaBeans;
|
||||
}
|
||||
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
for (int i = 0; i < deltaBeans.size(); i++) {
|
||||
deltaBeans.get(i).writeBinaryMessage(msgList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String,BeanDeltaList> deltaMap = new HashMap<String,BeanDeltaList>();
|
||||
|
||||
public BeanDeltaMap() {
|
||||
}
|
||||
|
||||
public BeanDeltaMap(List<BeanDelta> 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<BeanDeltaList> 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<String,BeanDeltaList> deltaMap = new HashMap<String,BeanDeltaList>();
|
||||
|
||||
public BeanDeltaMap() {
|
||||
}
|
||||
|
||||
public BeanDeltaMap(List<BeanDelta> 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<BeanDeltaList> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String,BeanPathUpdateIds> map = new LinkedHashMap<String, BeanPathUpdateIds>();
|
||||
|
||||
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<String,BeanPathUpdateIds> map = new LinkedHashMap<String, BeanPathUpdateIds>();
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Serializable> 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<Serializable> readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
|
||||
|
||||
int count = dataInput.readInt();
|
||||
if (count < 1) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<Serializable> idList = new ArrayList<Serializable>(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.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
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<Serializable> 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<Serializable> 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<Serializable> readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
|
||||
|
||||
int count = dataInput.readInt();
|
||||
if (count < 1) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<Serializable> idList = new ArrayList<Serializable>(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.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
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<Serializable> getIds() {
|
||||
return ids;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String,BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
|
||||
|
||||
public String toString() {
|
||||
return beanMap.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return beanMap.isEmpty();
|
||||
}
|
||||
|
||||
public Collection<BeanPersistIds> 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<String,BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
|
||||
|
||||
public String toString() {
|
||||
return beanMap.toString();
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return beanMap.isEmpty();
|
||||
}
|
||||
|
||||
public Collection<BeanPersistIds> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
* <p>
|
||||
* This information is broadcast across the cluster so that remote BeanListeners
|
||||
* are notified of the inserts updates and deletes that occured.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPersistIds implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8389469180931531409L;
|
||||
|
||||
private transient BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
private final String descriptorId;
|
||||
|
||||
private ArrayList<Serializable> insertIds;
|
||||
private ArrayList<Serializable> updateIds;
|
||||
private ArrayList<Serializable> deleteIds;
|
||||
|
||||
/**
|
||||
* Create the payload.
|
||||
*/
|
||||
public BeanPersistIds(BeanDescriptor<?> desc) {
|
||||
this.beanDescriptor = desc;
|
||||
this.descriptorId = desc.getDescriptorId();
|
||||
}
|
||||
|
||||
public static BeanPersistIds readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
|
||||
|
||||
String descriptorId = dataInput.readUTF();
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptorById(descriptorId);
|
||||
BeanPersistIds bp = new BeanPersistIds(desc);
|
||||
bp.read(dataInput);
|
||||
return bp;
|
||||
}
|
||||
|
||||
private void read(DataInput dataInput) throws IOException {
|
||||
|
||||
IdBinder idBinder = beanDescriptor.getIdBinder();
|
||||
|
||||
int iudType = dataInput.readInt();
|
||||
ArrayList<Serializable> idList = readIdList(dataInput, idBinder);
|
||||
|
||||
switch (iudType) {
|
||||
case 0:
|
||||
insertIds = idList;
|
||||
break;
|
||||
case 1:
|
||||
updateIds = idList;
|
||||
break;
|
||||
case 2:
|
||||
deleteIds = idList;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid iudType "+iudType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents into a BinaryMessage form.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
writeIdList(beanDescriptor, 0, insertIds, msgList);
|
||||
writeIdList(beanDescriptor, 1, updateIds, msgList);
|
||||
writeIdList(beanDescriptor, 2, deleteIds, msgList);
|
||||
|
||||
}
|
||||
|
||||
private ArrayList<Serializable> readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
|
||||
|
||||
int count = dataInput.readInt();
|
||||
if (count < 1) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<Serializable> idList = new ArrayList<Serializable>(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.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
private void writeIdList(BeanDescriptor<?> desc, int iudType, ArrayList<Serializable> 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<Serializable>();
|
||||
}
|
||||
insertIds.add(id);
|
||||
}
|
||||
|
||||
private void addUpdateId(Serializable id) {
|
||||
if (updateIds == null) {
|
||||
updateIds = new ArrayList<Serializable>();
|
||||
}
|
||||
updateIds.add(id);
|
||||
}
|
||||
|
||||
private void addDeleteId(Serializable id) {
|
||||
if (deleteIds == null) {
|
||||
deleteIds = new ArrayList<Serializable>();
|
||||
}
|
||||
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<Serializable> getInsertIds() {
|
||||
return insertIds;
|
||||
}
|
||||
|
||||
public List<Serializable> getUpdateIds() {
|
||||
return updateIds;
|
||||
}
|
||||
|
||||
public List<Serializable> 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.
|
||||
* <p>
|
||||
* This information is broadcast across the cluster so that remote BeanListeners
|
||||
* are notified of the inserts updates and deletes that occured.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public class BeanPersistIds implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8389469180931531409L;
|
||||
|
||||
private transient BeanDescriptor<?> beanDescriptor;
|
||||
|
||||
private final String descriptorId;
|
||||
|
||||
private ArrayList<Serializable> insertIds;
|
||||
private ArrayList<Serializable> updateIds;
|
||||
private ArrayList<Serializable> deleteIds;
|
||||
|
||||
/**
|
||||
* Create the payload.
|
||||
*/
|
||||
public BeanPersistIds(BeanDescriptor<?> desc) {
|
||||
this.beanDescriptor = desc;
|
||||
this.descriptorId = desc.getDescriptorId();
|
||||
}
|
||||
|
||||
public static BeanPersistIds readBinaryMessage(SpiEbeanServer server, DataInput dataInput) throws IOException {
|
||||
|
||||
String descriptorId = dataInput.readUTF();
|
||||
BeanDescriptor<?> desc = server.getBeanDescriptorById(descriptorId);
|
||||
BeanPersistIds bp = new BeanPersistIds(desc);
|
||||
bp.read(dataInput);
|
||||
return bp;
|
||||
}
|
||||
|
||||
private void read(DataInput dataInput) throws IOException {
|
||||
|
||||
IdBinder idBinder = beanDescriptor.getIdBinder();
|
||||
|
||||
int iudType = dataInput.readInt();
|
||||
ArrayList<Serializable> idList = readIdList(dataInput, idBinder);
|
||||
|
||||
switch (iudType) {
|
||||
case 0:
|
||||
insertIds = idList;
|
||||
break;
|
||||
case 1:
|
||||
updateIds = idList;
|
||||
break;
|
||||
case 2:
|
||||
deleteIds = idList;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new RuntimeException("Invalid iudType "+iudType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the contents into a BinaryMessage form.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public void writeBinaryMessage(BinaryMessageList msgList) throws IOException {
|
||||
|
||||
writeIdList(beanDescriptor, 0, insertIds, msgList);
|
||||
writeIdList(beanDescriptor, 1, updateIds, msgList);
|
||||
writeIdList(beanDescriptor, 2, deleteIds, msgList);
|
||||
|
||||
}
|
||||
|
||||
private ArrayList<Serializable> readIdList(DataInput dataInput, IdBinder idBinder) throws IOException {
|
||||
|
||||
int count = dataInput.readInt();
|
||||
if (count < 1) {
|
||||
return null;
|
||||
}
|
||||
ArrayList<Serializable> idList = new ArrayList<Serializable>(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.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
private void writeIdList(BeanDescriptor<?> desc, int iudType, ArrayList<Serializable> 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<Serializable>();
|
||||
}
|
||||
insertIds.add(id);
|
||||
}
|
||||
|
||||
private void addUpdateId(Serializable id) {
|
||||
if (updateIds == null) {
|
||||
updateIds = new ArrayList<Serializable>();
|
||||
}
|
||||
updateIds.add(id);
|
||||
}
|
||||
|
||||
private void addDeleteId(Serializable id) {
|
||||
if (deleteIds == null) {
|
||||
deleteIds = new ArrayList<Serializable>();
|
||||
}
|
||||
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<Serializable> getInsertIds() {
|
||||
return insertIds;
|
||||
}
|
||||
|
||||
public List<Serializable> getUpdateIds() {
|
||||
return updateIds;
|
||||
}
|
||||
|
||||
public List<Serializable> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+210
-210
@@ -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.
|
||||
* <p>
|
||||
* Ensures only one instance of a bean is used according to its type and unique
|
||||
* id.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
|
||||
/**
|
||||
* Map used hold caches. One cache per bean type.
|
||||
*/
|
||||
private final HashMap<String, ClassContext> typeCache = new HashMap<String, ClassContext>();
|
||||
|
||||
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<Object, Object> map = new HashMap<Object, Object>();
|
||||
|
||||
private Set<Object> deleteSet;
|
||||
|
||||
private ClassContext() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "size:" + map.size();
|
||||
}
|
||||
|
||||
private WithOption getWithOption(Object id) {
|
||||
if (deleteSet != null && deleteSet.contains(id)) {
|
||||
return WithOption.DELETED;
|
||||
}
|
||||
Object bean = map.get(id);
|
||||
return (bean == null) ? null : new WithOption(bean);
|
||||
}
|
||||
|
||||
private Object get(Object id) {
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
private Object putIfAbsent(Object id, Object bean) {
|
||||
|
||||
Object existingValue = map.get(id);
|
||||
if (existingValue != null) {
|
||||
// it is not absent
|
||||
return existingValue;
|
||||
}
|
||||
// put the new value and return null indicating the put was successful
|
||||
map.put(id, bean);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void put(Object id, Object b) {
|
||||
map.put(id, b);
|
||||
}
|
||||
|
||||
private int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
private Object remove(Object id) {
|
||||
return map.remove(id);
|
||||
}
|
||||
|
||||
private void deleted(Object id) {
|
||||
if (deleteSet == null) {
|
||||
deleteSet = new HashSet<Object>();
|
||||
}
|
||||
deleteSet.add(id);
|
||||
map.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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.
|
||||
* <p>
|
||||
* Ensures only one instance of a bean is used according to its type and unique
|
||||
* id.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
public final class DefaultPersistenceContext implements PersistenceContext {
|
||||
|
||||
/**
|
||||
* Map used hold caches. One cache per bean type.
|
||||
*/
|
||||
private final HashMap<String, ClassContext> typeCache = new HashMap<String, ClassContext>();
|
||||
|
||||
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<Object, Object> map = new HashMap<Object, Object>();
|
||||
|
||||
private Set<Object> deleteSet;
|
||||
|
||||
private ClassContext() {
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "size:" + map.size();
|
||||
}
|
||||
|
||||
private WithOption getWithOption(Object id) {
|
||||
if (deleteSet != null && deleteSet.contains(id)) {
|
||||
return WithOption.DELETED;
|
||||
}
|
||||
Object bean = map.get(id);
|
||||
return (bean == null) ? null : new WithOption(bean);
|
||||
}
|
||||
|
||||
private Object get(Object id) {
|
||||
return map.get(id);
|
||||
}
|
||||
|
||||
private Object putIfAbsent(Object id, Object bean) {
|
||||
|
||||
Object existingValue = map.get(id);
|
||||
if (existingValue != null) {
|
||||
// it is not absent
|
||||
return existingValue;
|
||||
}
|
||||
// put the new value and return null indicating the put was successful
|
||||
map.put(id, bean);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void put(Object id, Object b) {
|
||||
map.put(id, b);
|
||||
}
|
||||
|
||||
private int size() {
|
||||
return map.size();
|
||||
}
|
||||
|
||||
private void clear() {
|
||||
map.clear();
|
||||
}
|
||||
|
||||
private Object remove(Object id) {
|
||||
return map.remove(id);
|
||||
}
|
||||
|
||||
private void deleted(Object id) {
|
||||
if (deleteSet == null) {
|
||||
deleteSet = new HashSet<Object>();
|
||||
}
|
||||
deleteSet.add(id);
|
||||
map.remove(id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+128
-128
@@ -1,128 +1,128 @@
|
||||
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<TransactionMap> local = new ThreadLocal<TransactionMap>() {
|
||||
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'.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* Designed to be put in a finally block instead of a rollback() in each catch
|
||||
* block.
|
||||
*
|
||||
* <pre>
|
||||
* Ebean.beingTransaction();
|
||||
* try {
|
||||
* // ... perform some actions in a single transaction
|
||||
*
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* // ensure transaction ended. If some error occurred then rollback()
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </p>
|
||||
*/
|
||||
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<TransactionMap> local = new ThreadLocal<TransactionMap>() {
|
||||
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'.
|
||||
* <p>
|
||||
* 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.
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* Designed to be put in a finally block instead of a rollback() in each catch
|
||||
* block.
|
||||
*
|
||||
* <pre>
|
||||
* Ebean.beingTransaction();
|
||||
* try {
|
||||
* // ... perform some actions in a single transaction
|
||||
*
|
||||
* Ebean.commitTransaction();
|
||||
*
|
||||
* } finally {
|
||||
* // ensure transaction ended. If some error occurred then rollback()
|
||||
* Ebean.endTransaction();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* </p>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<String,BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
|
||||
|
||||
public String toString() {
|
||||
return beanMap.toString();
|
||||
}
|
||||
|
||||
public void notifyCache() {
|
||||
for (BeanPersistIds deleteIds : beanMap.values()) {
|
||||
BeanDescriptor<?> d = deleteIds.getBeanDescriptor();
|
||||
List<Serializable> 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<BeanPersistIds> 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<Object> 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<String,BeanPersistIds> beanMap = new LinkedHashMap<String, BeanPersistIds>();
|
||||
|
||||
public String toString() {
|
||||
return beanMap.toString();
|
||||
}
|
||||
|
||||
public void notifyCache() {
|
||||
for (BeanPersistIds deleteIds : beanMap.values()) {
|
||||
BeanDescriptor<?> d = deleteIds.getBeanDescriptor();
|
||||
List<Serializable> 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<BeanPersistIds> 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<Object> 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
+48
-48
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+229
-229
@@ -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.
|
||||
* <p>
|
||||
* Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* This is used by Ebean to notify it's appropriate listeners and maintain it's server
|
||||
* cache etc.
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* When Ebean is notified (of the commit/rollback) it can then manage its
|
||||
* cache, notify BeanPersistListeners etc.
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* Returns null if there is no current spring transaction (lazy loading outside a spring txn etc).
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* This is used by Ebean to notify it's appropriate listeners and maintain it's server
|
||||
* cache etc.
|
||||
* </p>
|
||||
*/
|
||||
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.
|
||||
* <p>
|
||||
* When Ebean is notified (of the commit/rollback) it can then manage its
|
||||
* cache, notify BeanPersistListeners etc.
|
||||
* </p>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+163
-163
@@ -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.
|
||||
* <p>
|
||||
* This includes Cluster notification, and BeanPersistListeners.
|
||||
* </p>
|
||||
*/
|
||||
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<PersistRequestBean<?>> 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<PersistRequestBean<?>> 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.
|
||||
* <p>
|
||||
* This includes Cluster notification, and BeanPersistListeners.
|
||||
* </p>
|
||||
*/
|
||||
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<PersistRequestBean<?>> 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<PersistRequestBean<?>> 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+141
-141
@@ -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<BeanPersistIds> beanPersistList = new ArrayList<BeanPersistIds>();
|
||||
|
||||
private List<TableIUD> tableList;
|
||||
|
||||
private List<BeanDeltaList> 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<TableIUD>(4);
|
||||
}
|
||||
tableList.add(tableIud);
|
||||
}
|
||||
|
||||
public void addBeanDeltaList(BeanDeltaList deltaList){
|
||||
if (beanDeltaLists == null){
|
||||
beanDeltaLists = new ArrayList<BeanDeltaList>();
|
||||
}
|
||||
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<TableIUD> getTableIUDList() {
|
||||
return tableList;
|
||||
}
|
||||
|
||||
public List<BeanPersistIds> getBeanPersistList() {
|
||||
return beanPersistList;
|
||||
}
|
||||
|
||||
public List<BeanDeltaList> 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<BeanPersistIds> beanPersistList = new ArrayList<BeanPersistIds>();
|
||||
|
||||
private List<TableIUD> tableList;
|
||||
|
||||
private List<BeanDeltaList> 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<TableIUD>(4);
|
||||
}
|
||||
tableList.add(tableIud);
|
||||
}
|
||||
|
||||
public void addBeanDeltaList(BeanDeltaList deltaList){
|
||||
if (beanDeltaLists == null){
|
||||
beanDeltaLists = new ArrayList<BeanDeltaList>();
|
||||
}
|
||||
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<TableIUD> getTableIUDList() {
|
||||
return tableList;
|
||||
}
|
||||
|
||||
public List<BeanPersistIds> getBeanPersistList() {
|
||||
return beanPersistList;
|
||||
}
|
||||
|
||||
public List<BeanDeltaList> getBeanDeltaLists() {
|
||||
if (beanDeltaMap != null){
|
||||
beanDeltaLists.addAll(beanDeltaMap.deltaLists());
|
||||
}
|
||||
return beanDeltaLists;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String,State> map = new HashMap<String, State>();
|
||||
|
||||
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<String,State> map = new HashMap<String, State>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user