001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.object.tx;
006:
007: import com.tc.management.beans.tx.ClientTxMonitorMBean;
008: import com.tc.object.ObjectID;
009: import com.tc.object.TCObject;
010: import com.tc.object.change.TCChangeBuffer;
011: import com.tc.object.change.TCChangeBufferImpl;
012: import com.tc.object.dmi.DmiDescriptor;
013: import com.tc.object.lockmanager.api.Notify;
014: import com.tc.object.logging.RuntimeLogger;
015: import com.tc.util.Assert;
016:
017: import gnu.trove.TIntArrayList;
018:
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.IdentityHashMap;
022: import java.util.Iterator;
023: import java.util.LinkedList;
024: import java.util.List;
025: import java.util.Map;
026:
027: /**
028: * @author steve
029: */
030: public class ClientTransactionImpl extends AbstractClientTransaction {
031: private final RuntimeLogger runtimeLogger;
032: private final Map objectChanges = new HashMap();
033: private final Map newRoots = new HashMap();
034: private final List notifies = new LinkedList();
035: private final List dmis = new LinkedList();
036:
037: // used to keep things referenced until the transaction is completely ACKED
038: private final Map referenced = new IdentityHashMap();
039:
040: public ClientTransactionImpl(TransactionID txID,
041: RuntimeLogger logger) {
042: super (txID);
043: this .runtimeLogger = logger;
044: }
045:
046: public boolean isConcurrent() {
047: return this .getTransactionType().isConcurrent();
048: }
049:
050: public boolean hasChangesOrNotifies() {
051: return !(objectChanges.isEmpty() && newRoots.isEmpty() && notifies
052: .isEmpty());
053: }
054:
055: public boolean hasChanges() {
056: return !(objectChanges.isEmpty() && newRoots.isEmpty());
057: }
058:
059: public Map getNewRoots() {
060: return newRoots;
061: }
062:
063: public Map getChangeBuffers() {
064: return this .objectChanges;
065: }
066:
067: protected void basicLiteralValueChanged(TCObject source,
068: Object newValue, Object oldValue) {
069: if (runtimeLogger.fieldChangeDebug()) {
070: runtimeLogger.literalValueChanged(source, newValue);
071: }
072:
073: getOrCreateChangeBuffer(source).literalValueChanged(newValue);
074: // To prevent it gcing on us.
075: addReferenced(oldValue);
076: addReferenced(newValue);
077: }
078:
079: protected void basicFieldChanged(TCObject source, String classname,
080: String fieldname, Object newValue, int index) {
081: if (runtimeLogger.fieldChangeDebug()) {
082: runtimeLogger.fieldChanged(source, classname, fieldname,
083: newValue, index);
084: }
085:
086: getOrCreateChangeBuffer(source).fieldChanged(classname,
087: fieldname, newValue, index);
088: }
089:
090: protected void basicArrayChanged(TCObject source, int startPos,
091: Object array, int length) {
092: if (runtimeLogger.arrayChangeDebug()) {
093: runtimeLogger.arrayChanged(source, startPos, array);
094: }
095:
096: getOrCreateChangeBuffer(source).arrayChanged(startPos, array,
097: length);
098: }
099:
100: protected void basicLogicalInvoke(TCObject source, int method,
101: Object[] parameters) {
102: getOrCreateChangeBuffer(source).logicalInvoke(method,
103: parameters);
104: }
105:
106: protected void basicCreate(TCObject object) {
107: if (runtimeLogger.newManagedObjectDebug()) {
108: runtimeLogger.newManagedObject(object);
109: }
110:
111: getOrCreateChangeBuffer(object);
112: }
113:
114: protected void basicCreateRoot(String name, ObjectID root) {
115: newRoots.put(name, root);
116: }
117:
118: private TCChangeBuffer getOrCreateChangeBuffer(TCObject object) {
119: addReferenced(object.getPeerObject());
120:
121: TCChangeBuffer cb = (TCChangeBuffer) objectChanges.get(object);
122: if (cb == null) {
123: cb = new TCChangeBufferImpl(object);
124: objectChanges.put(object, cb);
125: }
126:
127: return cb;
128: }
129:
130: private void addReferenced(Object pojo) {
131: Assert.assertNotNull("pojo", pojo);
132: referenced.put(pojo, null);
133: }
134:
135: public Collection getReferencesOfObjectsInTxn() {
136: return referenced.keySet();
137: }
138:
139: public void addNotify(Notify notify) {
140: if (!notify.isNull())
141: notifies.add(notify);
142: }
143:
144: public List addNotifiesTo(List l) {
145: l.addAll(notifies);
146: return l;
147: }
148:
149: public String toString() {
150: return "ClientTransactionImpl [ " + getTransactionID() + " ]";
151: }
152:
153: public int getNotifiesCount() {
154: return notifies.size();
155: }
156:
157: public void updateMBean(ClientTxMonitorMBean txMBean) {
158: int modifiedObjectCount = 0;
159: final TIntArrayList writesPerObject = new TIntArrayList(
160: objectChanges.size());
161:
162: final Map creationCountByClass = new HashMap();
163: if (!objectChanges.isEmpty()) {
164: int currentIndex = 0;
165: for (Iterator iter = objectChanges.keySet().iterator(); iter
166: .hasNext(); currentIndex++) {
167: final TCChangeBuffer buffer = (TCChangeBuffer) objectChanges
168: .get(iter.next());
169: final TCObject tco = buffer.getTCObject();
170: if (tco.isNew()) {
171: final Class instanceClass = tco.getTCClass()
172: .getPeerClass();
173: Integer counter = (Integer) creationCountByClass
174: .get(instanceClass);
175: if (counter == null) {
176: counter = new Integer(1);
177: } else {
178: counter = new Integer(counter.intValue() + 1);
179: }
180: creationCountByClass.put(instanceClass, counter);
181: } else {
182: ++modifiedObjectCount;
183: }
184: writesPerObject.add(buffer.getTotalEventCount());
185: }
186: }
187: txMBean.committedWriteTransaction(getNotifiesCount(),
188: modifiedObjectCount, writesPerObject.toNativeArray(),
189: creationCountByClass);
190: }
191:
192: public void addDmiDescritor(DmiDescriptor dd) {
193: dmis.add(dd);
194: }
195:
196: public List getDmiDescriptors() {
197: return dmis;
198: }
199:
200: }
|