1 4 package com.tc.object.change; 5 6 import com.tc.io.TCByteBufferOutputStream; 7 import com.tc.logging.TCLogger; 8 import com.tc.logging.TCLogging; 9 import com.tc.object.TCClass; 10 import com.tc.object.TCObject; 11 import com.tc.object.change.event.ArrayElementChangeEvent; 12 import com.tc.object.change.event.LiteralChangeEvent; 13 import com.tc.object.change.event.LogicalChangeEvent; 14 import com.tc.object.change.event.PhysicalChangeEvent; 15 import com.tc.object.dna.api.DNACursor; 16 import com.tc.object.dna.api.DNAWriter; 17 import com.tc.object.dna.api.LogicalAction; 18 import com.tc.object.dna.api.PhysicalAction; 19 import com.tc.object.dna.impl.DNAEncoding; 20 import com.tc.object.dna.impl.DNAWriterImpl; 21 import com.tc.object.dna.impl.ObjectStringSerializer; 22 import com.tc.object.tx.optimistic.OptimisticTransactionManager; 23 import com.tc.util.Assert; 24 import com.tc.util.concurrent.SetOnceFlag; 25 26 import java.util.Collection ; 27 import java.util.HashMap ; 28 import java.util.Iterator ; 29 import java.util.LinkedHashMap ; 30 import java.util.LinkedList ; 31 import java.util.List ; 32 import java.util.Map ; 33 34 37 public class TCChangeBufferImpl implements TCChangeBuffer { 38 private static final TCLogger logger = TCLogging.getLogger(TCChangeBuffer.class); 39 40 private final SetOnceFlag dnaCreated = new SetOnceFlag(); 41 private final TCObject tcObject; 42 43 private final int type; 44 private final Map physicalEvents; 45 private final List logicalEvents; 46 private final Map arrayEvents; 47 private final List literalValueChangedEvents; 48 49 public TCChangeBufferImpl(TCObject object) { 50 this.tcObject = object; 51 52 TCClass clazz = tcObject.getTCClass(); 55 if (clazz.isIndexed()) { 56 type = ARRAY; 57 physicalEvents = null; 58 literalValueChangedEvents = null; 59 logicalEvents = null; 60 arrayEvents = new LinkedHashMap (); 61 } else if (clazz.isLogical()) { 62 type = LOGICAL; 63 physicalEvents = null; 64 literalValueChangedEvents = null; 65 logicalEvents = new LinkedList (); 66 arrayEvents = null; 67 } else { 68 type = PHYSICAL; 69 physicalEvents = new HashMap (); 70 literalValueChangedEvents = new LinkedList (); 71 logicalEvents = null; 72 arrayEvents = null; 73 } 74 } 75 76 public void writeTo(TCByteBufferOutputStream output, ObjectStringSerializer serializer, DNAEncoding encoding) { 77 79 if (dnaCreated.attemptSet()) { 80 boolean commitNew = tcObject.getAndResetNew(); 81 82 TCClass tcClass = tcObject.getTCClass(); 83 String className = tcClass.getExtendingClassName(); 84 String loaderDesc = tcClass.getDefiningLoaderDescription(); 85 DNAWriter writer = new DNAWriterImpl(output, tcObject.getObjectID(), className, serializer, encoding, loaderDesc, 86 !commitNew); 87 88 if (commitNew) { 89 tcObject.dehydrate(writer); 90 } else { 91 if (arrayEvents != null) { 92 writeEventsToDNA(arrayEvents.values(), writer); 93 } 94 if (physicalEvents != null) { 95 writeEventsToDNA(physicalEvents.values(), writer); 96 } 97 if (logicalEvents != null) { 98 writeEventsToDNA(logicalEvents, writer); 99 } 100 if (literalValueChangedEvents != null) { 101 writeEventsToDNA(literalValueChangedEvents, writer); 102 } 103 } 104 105 writer.finalizeDNA(); 106 return; 107 } 108 109 throw new IllegalStateException ("DNA already created"); 110 } 111 112 private void writeEventsToDNA(Collection events, DNAWriter writer) { 113 if (events.size() > 0) { 114 for (Iterator iter = events.iterator(); iter.hasNext();) { 115 TCChangeBufferEvent event = (TCChangeBufferEvent) iter.next(); 116 event.write(writer); 117 } 118 } 119 } 120 121 public void literalValueChanged(Object newValue) { 122 literalValueChangedEvents.add(new LiteralChangeEvent(newValue)); 123 } 124 125 public void fieldChanged(String classname, String fieldname, Object newValue, int index) { 126 Assert.eval(newValue != null); 127 128 if (index >= 0) { 129 132 Integer key = new Integer (index); 134 arrayEvents.remove(key); 135 arrayEvents.put(key, new ArrayElementChangeEvent(index, newValue)); 136 } else { 137 if (logicalEvents != null) { 138 if (logger.isDebugEnabled()) { 141 logger.debug("Ignoring physical field change for " + classname + "." + fieldname + " since " 142 + tcObject.getTCClass().getName() + " is logically managed"); 143 } 144 return; 145 } 146 147 151 physicalEvents.put(fieldname, new PhysicalChangeEvent(fieldname, newValue)); 154 } 155 } 156 157 public void arrayChanged(int startPos, Object array, int newLength) { 158 Integer key = new Integer (-startPos); ArrayElementChangeEvent oldEvent = (ArrayElementChangeEvent) arrayEvents.remove(key); 161 if (oldEvent != null) { 162 Object oldArray = oldEvent.getValue(); 163 int oldLength = oldEvent.getLength(); 164 if (oldLength > newLength) { 165 System.arraycopy(array, 0, oldArray, 0, newLength); 166 array = oldArray; 167 } 168 } 169 arrayEvents.put(key, new ArrayElementChangeEvent(startPos, array, newLength)); 170 } 171 172 public void logicalInvoke(int method, Object [] parameters) { 173 177 logicalEvents.add(new LogicalChangeEvent(method, parameters)); 178 } 179 180 public TCObject getTCObject() { 181 return tcObject; 182 } 183 184 public int getTotalEventCount() { 185 int eventCount = 0; 186 if (physicalEvents != null) { 187 eventCount += physicalEvents.size(); 188 } 189 if (literalValueChangedEvents != null) { 190 eventCount += literalValueChangedEvents.size(); 191 } 192 if (logicalEvents != null) { 193 eventCount += logicalEvents.size(); 194 } 195 if (arrayEvents != null) { 196 eventCount += arrayEvents.size(); 197 } 198 return eventCount; 199 } 200 201 public int getType() { 202 return type; 203 } 204 205 public void accept(TCChangeBufferEventVisitor visitor) { 206 switch (type) { 207 case LOGICAL: 208 for (Iterator it = logicalEvents.iterator(); it.hasNext();) { 209 visitor.visitLogicalEvent((LogicalChangeEvent) it.next()); 210 } 211 break; 212 213 case PHYSICAL: 214 if (literalValueChangedEvents != null && literalValueChangedEvents.size() > 0) { throw new AssertionError ( 215 "Changes to literal roots are not supported in OptimisticTransaction."); } 216 for (Iterator it = physicalEvents.values().iterator(); it.hasNext();) { 217 visitor.visitPhysicalChangeEvent((PhysicalChangeEvent) it.next()); 218 } 219 break; 220 221 case ARRAY: 222 for (Iterator it = arrayEvents.values().iterator(); it.hasNext();) { 223 visitor.visitArrayElementChangeEvent((ArrayElementChangeEvent) it.next()); 224 } 225 break; 226 227 default: 228 throw new AssertionError ("Unknown event type " + type); 229 } 230 } 231 232 public DNACursor getDNACursor(OptimisticTransactionManager transactionManager) { 233 switch (type) { 234 case PHYSICAL: 235 if (literalValueChangedEvents != null && literalValueChangedEvents.size() > 0) { throw new AssertionError ( 236 "Changes to literal roots are not supported in OptimisticTransaction."); } 237 return new AbstractDNACursor(physicalEvents.values(), transactionManager) { 238 Object createNextAction(Object object) { 239 PhysicalChangeEvent pe = (PhysicalChangeEvent) object; 240 return new PhysicalAction(pe.getFieldName(), convertToParameter(pe.getNewValue()), pe.isReference()); 241 } 242 }; 243 244 case LOGICAL: 245 return new AbstractDNACursor(logicalEvents, transactionManager) { 246 Object createNextAction(Object object) { 247 LogicalChangeEvent le = (LogicalChangeEvent) object; 248 Object [] p = new Object [le.getParameters().length]; 249 for (int i = 0; i < le.getParameters().length; i++) { 250 p[i] = convertToParameter(le.getParameters()[i]); 251 } 252 return new LogicalAction(le.getMethodID(), p); 253 } 254 }; 255 256 case ARRAY: 257 return new AbstractDNACursor(arrayEvents.values(), transactionManager) { 258 Object createNextAction(Object object) { 259 ArrayElementChangeEvent ae = (ArrayElementChangeEvent) object; 260 if (ae.isSubarray()) { 261 return new PhysicalAction(ae.getValue(), ae.getIndex()); 262 } else { 263 return new PhysicalAction(ae.getIndex(), convertToParameter(ae.getValue()), ae.isReference()); 264 } 265 } 266 }; 267 268 default: 269 throw new AssertionError ("Unknown event type " + type); 270 } 271 } 272 273 private static abstract class AbstractDNACursor implements DNACursor { 274 private final OptimisticTransactionManager transactionManager; 275 private final Iterator iterator; 276 private final int size; 277 278 private Object currentAction = null; 279 280 public AbstractDNACursor(Collection values, OptimisticTransactionManager transactionManager) { 281 this.transactionManager = transactionManager; 282 this.iterator = values.iterator(); 283 this.size = values.size(); 284 } 285 286 public boolean next() { 287 boolean hasNext = iterator.hasNext(); 288 if (hasNext) { 289 this.currentAction = createNextAction(iterator.next()); 290 } 291 return hasNext; 292 } 293 294 abstract Object createNextAction(Object object); 295 296 public boolean next(DNAEncoding encoding) { 297 return next(); 298 } 299 300 public int getActionCount() { 301 return size; 302 } 303 304 public Object getAction() { 305 return currentAction; 306 } 307 308 public LogicalAction getLogicalAction() { 309 return (LogicalAction) currentAction; 310 } 311 312 public PhysicalAction getPhysicalAction() { 313 return (PhysicalAction) currentAction; 314 } 315 316 public void reset() throws UnsupportedOperationException { 317 throw new UnsupportedOperationException ("This operation is not supported by this class."); 318 } 319 320 protected Object convertToParameter(Object object) { 321 return transactionManager.convertToParameter(object); 322 } 323 } 324 325 } 326 | Popular Tags |