/*******************************************************************************
* Copyright 2005-2007, CHISEL Group, University of Victoria, Victoria, BC, Canada
* and IBM Corporation. All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* The Chisel Group, University of Victoria
*******************************************************************************/
package net.sourceforge.tagsea.resources.synchronize.ui;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import net.sourceforge.tagsea.resources.ResourceWaypointPlugin;
import net.sourceforge.tagsea.resources.synchronize.WaypointSynchronizeObject;
import net.sourceforge.tagsea.resources.waypoints.IResourceWaypointDescriptor;
import net.sourceforge.tagsea.resources.waypoints.operations.WaypointProjectXMLWriteOperation;
import net.sourceforge.tagsea.resources.waypoints.xml.WaypointXMLUtilities;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.team.core.RepositoryProvider;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.history.IFileHistory;
import org.eclipse.team.core.history.IFileHistoryProvider;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.internal.ccvs.core.filehistory.CVSFileHistory;
import org.xml.sax.SAXException;
/**
* Checks a given project for waypoints in the local system as well as the remote storage and creates
* object that represent both the local and the remote waypoints.
* @author Del Myers
*
*/
public class ProjectWaypointSynchronizeFinder implements IRunnableWithProgress {
List<WaypointSynchronizeObject> synchronizers;
private static class DescriptorComparator implements Comparator<IResourceWaypointDescriptor> {
public int compare(IResourceWaypointDescriptor o1, IResourceWaypointDescriptor o2) {
return (o1.getResource()+o1.getStamp()).compareTo(o2.getResource()+o2.getStamp());
}
}
private IProject project;
ProjectWaypointSynchronizeFinder(IProject project) {
this.project = project;
}
/* (non-Javadoc)
* @see org.eclipse.jface.operation.IRunnableWithProgress#run(org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(IProgressMonitor monitor) throws InvocationTargetException,
InterruptedException {
//clear the list.
synchronizers = new ArrayList<WaypointSynchronizeObject>();
monitor.beginTask("Collecting synchronization data...", 300);
SubProgressMonitor saveMonitor =
new SubProgressMonitor(monitor, 100, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
monitor.subTask("Saving waypoints...");
WaypointProjectXMLWriteOperation writer = new WaypointProjectXMLWriteOperation(project);
writer.run(saveMonitor);
if (monitor.isCanceled())
throw new InterruptedException();
IFile waypointFile = project.getFile(".resourceWaypoints");
IResourceWaypointDescriptor[] localDescriptors = new IResourceWaypointDescriptor[0];
if (waypointFile.exists()) {
try {
localDescriptors = WaypointXMLUtilities.loadFile(WaypointXMLUtilities.getWaypointFile(project));
} catch (IOException e) {
} catch (SAXException e) {
ResourceWaypointPlugin.getDefault().log(e);
return;
}
}
//@tag tagsea.bug.50.enhance : consider using the subscriber to cache data instead.
RepositoryProvider provider = RepositoryProvider.getProvider(project);
SubProgressMonitor historyMonitor =
new SubProgressMonitor(monitor, 100, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
monitor.subTask("Getting remote history...");
IFileRevision revision = provider.getFileHistoryProvider().getWorkspaceFileRevision(waypointFile);
try {
if (revision != null)
revision = revision.withAllProperties(new NullProgressMonitor());
} catch (CoreException e1) {
throw new InvocationTargetException(e1);
}
IFileHistory history = provider.getFileHistoryProvider().getFileHistoryFor(waypointFile,IFileHistoryProvider.SINGLE_REVISION, historyMonitor);
if (history instanceof CVSFileHistory) {
//@tag tagsea.bug.50.hack -author="Del Myers" -date="enCA:21/02/07" : CVSFileHistory doesn't refresh itself.
//I don't know why the CVSFileHistory doesn't refresh itself. This seems silly because you
//can never be sure using the interface methods whether or not the revision history has been refreshed.
try {
((CVSFileHistory)history).refresh(new NullProgressMonitor());
} catch (TeamException e) {
}
}
IResourceWaypointDescriptor[] remoteDescriptors = new IResourceWaypointDescriptor[0];
if (history != null) {
IFileRevision[] revisions = history.getFileRevisions();
SubProgressMonitor downloadMonitor =
new SubProgressMonitor(monitor, 50, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
monitor.subTask("Getting remote data...");
if (revisions.length > 0) {
try {
IStorage storage = revisions[0].getStorage(downloadMonitor);
remoteDescriptors = WaypointXMLUtilities.load(storage.getContents());
} catch (CoreException e) {
ResourceWaypointPlugin.getDefault().log(e);
return;
} catch (SAXException e) {
ResourceWaypointPlugin.getDefault().log(e);
return;
} catch (IOException e) {
}
}
} else {
monitor.worked(50);
}
if (monitor.isCanceled())
throw new InterruptedException();
monitor.subTask("Organizing changes...");
long time = (revision != null) ? revision.getTimestamp() : -1;
organizeDescriptors(time, localDescriptors, remoteDescriptors);
monitor.done();
}
/**
* Sorts and organizes the local and remote descriptors to group waypoint changes.
*
* @param localDescriptors
* @param remoteDescriptors
*/
private void organizeDescriptors(long workspaceRevision, IResourceWaypointDescriptor[] localDescriptors, IResourceWaypointDescriptor[] remoteDescriptors) {
Arrays.sort(localDescriptors, new DescriptorComparator());
Arrays.sort(remoteDescriptors, new DescriptorComparator());
int li = 0;
int ri = 0;
boolean done = false;
List<WaypointSynchronizeObject> synchronizeObjects = new ArrayList<WaypointSynchronizeObject>();
while (!done) {
if (li >= localDescriptors.length) {
done = true;
}
if (ri >= remoteDescriptors.length) {
done = true;
}
if (!done) {
String lstamp = localDescriptors[li].getStamp();
String rstamp = remoteDescriptors[ri].getStamp();
int diff = lstamp.compareTo(rstamp);
if (diff == 0) {
//same waypoint create a synchronize object that contains both.
WaypointSynchronizeObject so =
new WaypointSynchronizeObject(project, workspaceRevision, localDescriptors[li], localDescriptors[ri]);
synchronizeObjects.add(so);
li++;
ri++;
} else if (diff < 0) {
//the local waypoint does not exist in the remote repository... add it.
synchronizeObjects.add(
new WaypointSynchronizeObject(project, workspaceRevision, localDescriptors[li], null)
);
li++;
} else if (diff > 0) {
// the remote waypoint does not exist locally... add it.
synchronizeObjects.add(
new WaypointSynchronizeObject(project, workspaceRevision, null, remoteDescriptors[ri])
);
ri++;
}
}
}
while (li < localDescriptors.length) {
synchronizeObjects.add(
new WaypointSynchronizeObject(project, workspaceRevision, localDescriptors[li], null)
);
li++;
}
while (ri < remoteDescriptors.length) {
synchronizeObjects.add(
new WaypointSynchronizeObject(project, workspaceRevision, null, remoteDescriptors[ri])
);
ri++;
}
synchronizers = synchronizeObjects;
}
/**
* @return the synchronizers
*/
public List<WaypointSynchronizeObject> getSynchronizers() {
return synchronizers;
}
}