1 11 package org.eclipse.team.core.variants; 12 13 import java.util.*; 14 15 import org.eclipse.core.resources.*; 16 import org.eclipse.core.runtime.*; 17 import org.eclipse.core.runtime.jobs.ILock; 18 import org.eclipse.core.runtime.jobs.ISchedulingRule; 19 import org.eclipse.team.core.TeamException; 20 import org.eclipse.team.internal.core.Policy; 21 import org.eclipse.team.internal.core.subscribers.BatchingLock; 22 import org.eclipse.team.internal.core.subscribers.SyncByteConverter; 23 import org.eclipse.team.internal.core.subscribers.BatchingLock.IFlushOperation; 24 import org.eclipse.team.internal.core.subscribers.BatchingLock.ThreadInfo; 25 26 38 public class ThreeWaySynchronizer implements IFlushOperation { 39 40 private static final byte[] IGNORED_BYTES = "i".getBytes(); 42 private ILock lock = Platform.getJobManager().newLock(); 43 private BatchingLock batchingLock = new BatchingLock(); 44 private ResourceVariantByteStore cache; 45 private Set listeners = new HashSet(); 46 47 53 public ThreeWaySynchronizer(QualifiedName name) { 54 this(new PersistantResourceVariantByteStore(name)); 55 } 56 57 62 public ThreeWaySynchronizer(ResourceVariantByteStore store) { 63 cache = store; 64 } 65 66 79 public void addListener(ISynchronizerChangeListener listener) { 80 synchronized (listeners) { 81 listeners.add(listener); 82 } 83 } 84 85 91 public void removeListener(ISynchronizerChangeListener listener) { 92 synchronized (listeners) { 93 listeners.remove(listener); 94 } 95 } 96 97 107 public byte[] getBaseBytes(IResource resource) throws TeamException { 108 try { 109 beginOperation(); 110 byte[] syncBytes = internalGetSyncBytes(resource); 111 if (syncBytes == null) return null; 112 byte[] baseBytes = getSlot(syncBytes, 1); 113 if (baseBytes == null || baseBytes.length == 0) return null; 114 return baseBytes; 115 } finally { 116 endOperation(); 117 } 118 } 119 120 133 public void setBaseBytes(IResource resource, byte[] baseBytes) throws TeamException { 134 Assert.isNotNull(baseBytes); 135 ISchedulingRule rule = null; 136 try { 137 rule = beginBatching(resource, null); 138 try { 139 beginOperation(); 140 String base = new String (baseBytes); 141 String [] slots = new String [] { 142 new Long (resource.getModificationStamp()).toString(), 143 base, 144 base 145 }; 146 byte[] syncBytes = toBytes(slots); 147 internalSetSyncBytes(resource, syncBytes); 148 batchingLock.resourceChanged(resource); 149 } finally { 150 endOperation(); 151 } 152 } finally { 153 if (rule != null) endBatching(rule, null); 154 } 155 } 156 157 167 public boolean isLocallyModified(IResource resource) throws TeamException { 168 return ((internalGetSyncBytes(resource) == null && ! isIgnored(resource)) || 169 (getLocalTimestamp(resource) != resource.getModificationStamp()) || 170 (getBaseBytes(resource) != null && !resource.exists())); 171 } 172 173 183 public byte[] getRemoteBytes(IResource resource) throws TeamException { 184 try { 185 beginOperation(); 186 byte[] syncBytes = internalGetSyncBytes(resource); 187 if (syncBytes == null) return null; 188 byte[] remoteBytes = getSlot(syncBytes, 2); 189 if (remoteBytes == null || remoteBytes.length == 0) return null; 190 return remoteBytes; 191 } finally { 192 endOperation(); 193 } 194 } 195 196 209 public boolean setRemoteBytes(IResource resource, byte[] remoteBytes) throws TeamException { 210 Assert.isNotNull(remoteBytes); 211 ISchedulingRule rule = null; 212 try { 213 rule = beginBatching(resource, null); 214 try { 215 beginOperation(); 216 byte[] syncBytes = internalGetSyncBytes(resource); 217 if (syncBytes == null) { 218 String [] slots = new String [] { 219 "", "", new String (remoteBytes) 222 }; 223 syncBytes = toBytes(slots); 224 } else { 225 byte[] currentRemote = getSlot(syncBytes, 2); 226 if (equals(remoteBytes, currentRemote)) return false; 227 syncBytes = setSlot(syncBytes, 2, remoteBytes); 228 } 229 internalSetSyncBytes(resource, syncBytes); 230 batchingLock.resourceChanged(resource); 231 return true; 232 } finally { 233 endOperation(); 234 } 235 } finally { 236 if (rule != null) endBatching(rule, null); 237 } 238 } 239 240 247 public boolean removeRemoteBytes(IResource resource) throws TeamException { 248 ISchedulingRule rule = null; 249 try { 250 rule = beginBatching(resource, null); 251 try { 252 beginOperation(); 253 byte[] syncBytes = internalGetSyncBytes(resource); 254 if (syncBytes != null) { 255 String currentRemote = new String (getSlot(syncBytes, 2)); 256 if (currentRemote.length() == 0) return false; 257 syncBytes = setSlot(syncBytes, 2, new byte[0]); 258 internalSetSyncBytes(resource, syncBytes); 259 batchingLock.resourceChanged(resource); 260 return true; 261 } 262 return false; 263 } finally { 264 endOperation(); 265 } 266 } finally { 267 if (rule != null) endBatching(rule, null); 268 } 269 } 270 271 276 public boolean hasSyncBytes(IResource resource) throws TeamException { 277 return internalGetSyncBytes(resource) != null; 278 } 279 280 287 public boolean isIgnored(IResource resource) throws TeamException { 288 byte[] bytes = cache.getBytes(resource); 289 return (bytes != null && equals(bytes, IGNORED_BYTES)); 290 } 291 292 300 public void setIgnored(IResource resource) throws TeamException { 301 internalSetSyncBytes(resource, IGNORED_BYTES); 302 } 303 304 312 public IResource[] members(IResource resource) throws TeamException { 313 if (resource.getType() == IResource.FILE) { 314 return new IResource[0]; 315 } 316 try { 317 Set potentialChildren = new HashSet(); 318 IContainer container = (IContainer)resource; 319 if (container.exists()) { 320 potentialChildren.addAll(Arrays.asList(container.members())); 321 } 322 potentialChildren.addAll(Arrays.asList(cache.members(resource))); 323 List result = new ArrayList(); 324 for (Iterator iter = potentialChildren.iterator(); iter.hasNext();) { 325 IResource child = (IResource) iter.next(); 326 if (child.exists() || hasSyncBytes(child)) { 327 result.add(child); 328 } 329 } 330 return (IResource[]) result.toArray(new IResource[result.size()]); 331 } catch (CoreException e) { 332 throw TeamException.asTeamException(e); 333 } 334 } 335 336 343 public void flush(IResource resource, int depth) throws TeamException { 344 ISchedulingRule rule = null; 345 try { 346 rule = beginBatching(resource, null); 347 try { 348 beginOperation(); 349 if (cache.flushBytes(resource, depth)) { 350 batchingLock.resourceChanged(resource); 351 } 352 } finally { 353 endOperation(); 354 } 355 } finally { 356 if (rule != null) endBatching(rule, null); 357 } 358 } 359 360 368 public void run(IResource resourceRule, IWorkspaceRunnable runnable, IProgressMonitor monitor) throws TeamException { 369 monitor = Policy.monitorFor(monitor); 370 monitor.beginTask(null, 100); 371 ISchedulingRule rule = beginBatching(resourceRule, Policy.subMonitorFor(monitor, 10)); 372 try { 373 cache.run(resourceRule, runnable, Policy.subMonitorFor(monitor, 80)); 374 } catch (CoreException e) { 375 throw TeamException.asTeamException(e); 376 } finally { 377 if (rule != null) endBatching(rule, Policy.subMonitorFor(monitor, 10)); 378 monitor.done(); 379 } 380 } 381 382 389 public void flush(ThreadInfo info, IProgressMonitor monitor) throws TeamException { 390 if (info != null && !info.isEmpty()) { 391 broadcastSyncChanges(info.getChangedResources()); 392 } 393 } 394 395 private void broadcastSyncChanges(final IResource[] resources) { 396 ISynchronizerChangeListener[] allListeners; 397 synchronized(listeners) { 399 allListeners = (ISynchronizerChangeListener[]) listeners.toArray(new ISynchronizerChangeListener[listeners.size()]); 400 } 401 for (int i = 0; i < allListeners.length; i++) { 403 final ISynchronizerChangeListener listener = allListeners[i]; 404 Platform.run(new ISafeRunnable() { 405 public void handleException(Throwable exception) { 406 } 408 public void run() throws Exception { 409 listener.syncStateChanged(resources); 410 411 } 412 }); 413 } 414 } 415 416 421 private byte[] internalGetSyncBytes(IResource resource) throws TeamException { 422 byte[] bytes = cache.getBytes(resource); 423 if (bytes != null && equals(bytes, IGNORED_BYTES)) return null; 424 return bytes; 425 } 426 427 430 private boolean internalSetSyncBytes(IResource resource, byte[] syncBytes) throws TeamException { 431 return cache.setBytes(resource, syncBytes); 432 } 433 434 private byte[] getSlot(byte[] syncBytes, int i) { 435 return SyncByteConverter.getSlot(syncBytes, i, false); 436 } 437 438 private byte[] setSlot(byte[] syncBytes, int i, byte[] insertBytes) throws TeamException { 439 return SyncByteConverter.setSlot(syncBytes, i, insertBytes); 440 } 441 442 private byte[] toBytes(String [] slots) { 443 return SyncByteConverter.toBytes(slots); 444 } 445 446 private long getLocalTimestamp(IResource resource) throws TeamException { 447 try { 448 beginOperation(); 449 byte[] syncBytes = internalGetSyncBytes(resource); 450 if (syncBytes == null) return -1; 451 byte[] bytes = getSlot(syncBytes, 0); 452 if (bytes == null || bytes.length == 0) return -1; 453 return Long.parseLong(new String (bytes)); 454 } finally { 455 endOperation(); 456 } 457 } 458 459 private boolean equals(byte[] syncBytes, byte[] oldBytes) { 460 if (syncBytes.length != oldBytes.length) return false; 461 for (int i = 0; i < oldBytes.length; i++) { 462 if (oldBytes[i] != syncBytes[i]) return false; 463 } 464 return true; 465 } 466 467 470 private void beginOperation() { 471 if (ResourcesPlugin.getWorkspace().isTreeLocked()) return; 477 lock.acquire(); 478 } 479 480 483 private void endOperation() { 484 if (ResourcesPlugin.getWorkspace().isTreeLocked()) return; 486 lock.release(); 487 } 488 489 495 private ISchedulingRule beginBatching(ISchedulingRule resourceRule, IProgressMonitor monitor) { 496 return batchingLock.acquire(resourceRule, this , monitor); 497 } 498 499 503 private void endBatching(ISchedulingRule rule, IProgressMonitor monitor) throws TeamException { 504 batchingLock.release(rule, monitor); 505 } 506 } 507 | Popular Tags |