1 19 20 package org.apache.cayenne; 21 22 import java.util.ArrayList ; 23 import java.util.Collection ; 24 import java.util.Iterator ; 25 26 import org.apache.cayenne.event.EventManager; 27 import org.apache.cayenne.event.EventSubject; 28 import org.apache.cayenne.graph.ArcCreateOperation; 29 import org.apache.cayenne.graph.ArcDeleteOperation; 30 import org.apache.cayenne.graph.GraphChangeHandler; 31 import org.apache.cayenne.graph.GraphDiff; 32 import org.apache.cayenne.graph.GraphEvent; 33 import org.apache.cayenne.graph.GraphMap; 34 import org.apache.cayenne.graph.NodeCreateOperation; 35 import org.apache.cayenne.graph.NodeDeleteOperation; 36 import org.apache.cayenne.graph.NodeIdChangeOperation; 37 import org.apache.cayenne.graph.NodePropertyChangeOperation; 38 39 46 final class CayenneContextGraphManager extends GraphMap { 47 48 static final String COMMIT_MARKER = "commit"; 49 static final String FLUSH_MARKER = "flush"; 50 51 CayenneContext context; 52 Collection deadIds; 53 boolean changeEventsEnabled; 54 boolean lifecycleEventsEnabled; 55 56 ObjectContextStateLog stateLog; 57 ObjectContextChangeLog changeLog; 58 59 CayenneContextGraphManager(CayenneContext context, boolean changeEventsEnabled, 60 boolean lifecycleEventsEnabled) { 61 62 this.context = context; 63 this.changeEventsEnabled = changeEventsEnabled; 64 this.lifecycleEventsEnabled = lifecycleEventsEnabled; 65 66 this.stateLog = new ObjectContextStateLog(this); 67 this.changeLog = new ObjectContextChangeLog(); 68 } 69 70 boolean hasChanges() { 71 return changeLog.size() > 0; 72 } 73 74 boolean hasChangesSinceLastFlush() { 75 int size = changeLog.hasMarker(FLUSH_MARKER) ? changeLog 76 .sizeAfterMarker(FLUSH_MARKER) : changeLog.size(); 77 return size > 0; 78 } 79 80 GraphDiff getDiffs() { 81 return changeLog.getDiffs(); 82 } 83 84 GraphDiff getDiffsSinceLastFlush() { 85 return changeLog.hasMarker(FLUSH_MARKER) ? changeLog 86 .getDiffsAfterMarker(FLUSH_MARKER) : changeLog.getDiffs(); 87 } 88 89 Collection dirtyNodes() { 90 return stateLog.dirtyNodes(); 91 } 92 93 Collection dirtyNodes(int state) { 94 return stateLog.dirtyNodes(state); 95 } 96 97 public synchronized Object unregisterNode(Object nodeId) { 98 Object node = super.unregisterNode(nodeId); 99 100 if (node != null) { 102 stateLog.unregisterNode(nodeId); 103 changeLog.unregisterNode(nodeId); 104 return node; 105 } 106 107 return null; 108 } 109 110 114 void graphCommitAborted() { 115 changeLog.removeMarker(COMMIT_MARKER); 116 } 117 118 122 void graphCommitStarted() { 123 changeLog.setMarker(COMMIT_MARKER); 124 } 125 126 void graphCommitted(GraphDiff parentSyncDiff) { 127 if (parentSyncDiff != null) { 128 new CayenneContextMergeHandler(context).merge(parentSyncDiff); 129 } 130 131 if (lifecycleEventsEnabled) { 132 GraphDiff diff = changeLog.getDiffsAfterMarker(COMMIT_MARKER); 133 134 stateLog.graphCommitted(); 135 reset(); 136 137 send(diff, DataChannel.GRAPH_FLUSHED_SUBJECT, context); 139 } 140 else { 141 stateLog.graphCommitted(); 142 reset(); 143 } 144 } 145 146 void graphFlushed() { 147 changeLog.setMarker(FLUSH_MARKER); 148 } 149 150 void graphReverted() { 151 GraphDiff diff = changeLog.getDiffs(); 152 153 diff.undo(new NullChangeHandler()); 154 stateLog.graphReverted(); 155 reset(); 156 157 if (lifecycleEventsEnabled) { 158 send(diff, DataChannel.GRAPH_ROLLEDBACK_SUBJECT, context); 159 } 160 } 161 162 165 public synchronized void nodeIdChanged(Object nodeId, Object newId) { 166 stateLog.nodeIdChanged(nodeId, newId); 167 processChange(new NodeIdChangeOperation(nodeId, newId)); 168 } 169 170 public synchronized void nodeCreated(Object nodeId) { 171 stateLog.nodeCreated(nodeId); 172 processChange(new NodeCreateOperation(nodeId)); 173 } 174 175 public synchronized void nodeRemoved(Object nodeId) { 176 stateLog.nodeRemoved(nodeId); 177 processChange(new NodeDeleteOperation(nodeId)); 178 } 179 180 public synchronized void nodePropertyChanged( 181 Object nodeId, 182 String property, 183 Object oldValue, 184 Object newValue) { 185 186 stateLog.nodePropertyChanged(nodeId, property, oldValue, newValue); 187 processChange(new NodePropertyChangeOperation( 188 nodeId, 189 property, 190 oldValue, 191 newValue)); 192 } 193 194 public synchronized void arcCreated(Object nodeId, Object targetNodeId, Object arcId) { 195 stateLog.arcCreated(nodeId, targetNodeId, arcId); 196 processChange(new ArcCreateOperation(nodeId, targetNodeId, arcId)); 197 } 198 199 public synchronized void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) { 200 stateLog.arcDeleted(nodeId, targetNodeId, arcId); 201 processChange(new ArcDeleteOperation(nodeId, targetNodeId, arcId)); 202 } 203 204 207 private void processChange(GraphDiff diff) { 208 changeLog.addOperation(diff); 209 210 if (changeEventsEnabled) { 211 send(diff, DataChannel.GRAPH_CHANGED_SUBJECT, context); 212 } 213 } 214 215 219 void send(GraphDiff diff, EventSubject subject, Object eventSource) { 220 EventManager manager = (context.getChannel() != null) ? context 221 .getChannel() 222 .getEventManager() : null; 223 224 if (manager != null) { 225 GraphEvent e = new GraphEvent(context, eventSource, diff); 226 manager.postEvent(e, subject); 227 } 228 } 229 230 void reset() { 231 changeLog.reset(); 232 233 if (deadIds != null) { 234 Iterator it = deadIds.iterator(); 236 while (it.hasNext()) { 237 nodes.remove(it.next()); 238 } 239 240 deadIds = null; 241 } 242 } 243 244 Collection deadIds() { 245 if (deadIds == null) { 246 deadIds = new ArrayList (); 247 } 248 249 return deadIds; 250 } 251 252 class NullChangeHandler implements GraphChangeHandler { 253 254 public void arcCreated(Object nodeId, Object targetNodeId, Object arcId) { 255 } 256 257 public void arcDeleted(Object nodeId, Object targetNodeId, Object arcId) { 258 } 259 260 public void nodeCreated(Object nodeId) { 261 } 262 263 public void nodeIdChanged(Object nodeId, Object newId) { 264 } 265 266 public void nodePropertyChanged( 267 Object nodeId, 268 String property, 269 Object oldValue, 270 Object newValue) { 271 } 272 273 public void nodeRemoved(Object nodeId) { 274 } 275 } 276 } 277 | Popular Tags |