// $codepro.audit.disable com.instantiations.assist.eclipse.analysis.audit.rule.effectivejava.alwaysOverridetoString.alwaysOverrideToString, com.instantiations.assist.eclipse.analysis.deserializeabilitySecurity, com.instantiations.assist.eclipse.analysis.enforceCloneableUsageSecurity | |
/******************************************************************************* | |
* Copyright (c) 2010, 2012 Ericsson AB and others. | |
* | |
* 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 | |
* | |
* Description: | |
* | |
* This class implements the context-sensitive command to find review items | |
* in the parent project to add to the review | |
* | |
* Contributors: | |
* Sebastien Dubois - Created for Mylyn Review R4E project | |
* | |
******************************************************************************/ | |
package org.eclipse.mylyn.reviews.r4e.ui.internal.commands.handlers; | |
import java.util.ArrayList; | |
import java.util.Collections; | |
import java.util.Date; | |
import java.util.List; | |
import java.util.concurrent.atomic.AtomicInteger; | |
import java.util.concurrent.locks.ReentrantLock; | |
import org.eclipse.compare.rangedifferencer.RangeDifference; | |
import org.eclipse.core.commands.AbstractHandler; | |
import org.eclipse.core.commands.ExecutionEvent; | |
import org.eclipse.core.commands.ExecutionException; | |
import org.eclipse.core.resources.IFolder; | |
import org.eclipse.core.resources.IProject; | |
import org.eclipse.core.runtime.CoreException; | |
import org.eclipse.core.runtime.IAdaptable; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.core.runtime.IStatus; | |
import org.eclipse.core.runtime.OperationCanceledException; | |
import org.eclipse.core.runtime.Status; | |
import org.eclipse.core.runtime.jobs.IJobChangeEvent; | |
import org.eclipse.core.runtime.jobs.ISchedulingRule; | |
import org.eclipse.core.runtime.jobs.Job; | |
import org.eclipse.core.runtime.jobs.JobChangeAdapter; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.jdt.core.IJavaElement; | |
import org.eclipse.jdt.core.IJavaProject; | |
import org.eclipse.jdt.core.IPackageFragment; | |
import org.eclipse.jdt.core.IPackageFragmentRoot; | |
import org.eclipse.jface.dialogs.ErrorDialog; | |
import org.eclipse.jface.viewers.ISelection; | |
import org.eclipse.jface.viewers.IStructuredSelection; | |
import org.eclipse.mylyn.reviews.frame.core.utils.Tracer; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EContextType; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EFileVersion; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EFormalReview; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EReview; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EReviewComponent; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EReviewPhase; | |
import org.eclipse.mylyn.reviews.r4e.core.model.R4EReviewType; | |
import org.eclipse.mylyn.reviews.r4e.core.model.serial.impl.OutOfSyncException; | |
import org.eclipse.mylyn.reviews.r4e.core.model.serial.impl.ResourceHandlingException; | |
import org.eclipse.mylyn.reviews.r4e.core.rfs.spi.IRFSRegistry; | |
import org.eclipse.mylyn.reviews.r4e.core.rfs.spi.RFSRegistryFactory; | |
import org.eclipse.mylyn.reviews.r4e.core.rfs.spi.ReviewsFileStorageException; | |
import org.eclipse.mylyn.reviews.r4e.ui.R4EUIPlugin; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.dialogs.R4EUIDialogFactory; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.editors.R4ECompareEditorInput; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.IR4EUIPosition; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIDeltaContainer; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIFileContext; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIModelController; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIReviewBasic; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUIReviewItem; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.model.R4EUITextPosition; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.preferences.PreferenceConstants; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.CommandUtils; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.Diff; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.DiffUtils; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.MailServicesProxy; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.R4EUIConstants; | |
import org.eclipse.mylyn.reviews.r4e.ui.internal.utils.UIUtils; | |
import org.eclipse.mylyn.versions.core.Change; | |
import org.eclipse.mylyn.versions.core.ChangeSet; | |
import org.eclipse.mylyn.versions.core.ScmArtifact; | |
import org.eclipse.mylyn.versions.ui.spi.ScmConnectorUi; | |
import org.eclipse.team.core.history.IFileRevision; | |
import org.eclipse.ui.handlers.HandlerUtil; | |
import org.eclipse.ui.progress.IProgressConstants; | |
/** | |
* @author Sebastien Dubois | |
* @version $Revision: 1.0 $ | |
*/ | |
public class FindReviewItemsHandler extends AbstractHandler { | |
// ------------------------------------------------------------------------ | |
// Constants | |
// ------------------------------------------------------------------------ | |
/** | |
* Field FETCH_JOB_FAMILY. (value is ""fetchFamily"") | |
*/ | |
private static final String FETCH_JOB_FAMILY = "fetchFamily"; | |
/** | |
* Field DELTA_JOB_FAMILY. (value is ""deltaFamily"") | |
*/ | |
private static final String DELTA_JOB_FAMILY = "deltaFamily"; | |
/** | |
* Field ADD_JOB_FAMILY. (value is ""addFamily"") | |
*/ | |
private static final String ADD_JOB_FAMILY = "addFamily"; | |
/** | |
* Field IMPORTING_FILES_MSG. (value is ""Importing Files..."") | |
*/ | |
private static final String IMPORTING_FILES_MSG = "Importing Files..."; | |
/** | |
* Field FETCHING_FILES_MSG. (value is ""Fetching Files..."") | |
*/ | |
private static final String FETCHING_FILES_MSG = "Fetching Files..."; | |
/** | |
* Field FETCHING_FILE_MSG. (value is ""Fetching File..."") | |
*/ | |
private static final String FETCHING_FILE_MSG = "Fetching File..."; | |
/** | |
* Field CALCULATE_DELTAS_MSG. (value is ""Computing differences..."") | |
*/ | |
private static final String CALCULATE_DELTAS_MSG = "Computing differences..."; | |
/** | |
* Field CALCULATE_DELTAS_FILE_MSG. (value is ""Computing differences for file "") | |
*/ | |
private static final String CALCULATE_DELTAS_FILE_MSG = "Computing differences for file "; | |
/** | |
* Field ADD_ELEMENT_MSG. (value is ""Adding Elements to R4E model..."") | |
*/ | |
private static final String ADD_ELEMENT_MSG = "Adding Elements to R4E model..."; | |
/** | |
* Field ADD_REVIEW_ITEM_MSG. (value is ""Adding Review Item to R4E Model..."") | |
*/ | |
private static final String ADD_REVIEW_ITEM_MSG = "Adding Review Item to R4E Model..."; | |
/** | |
* Field MAX_CONCURRRENT_JOBS. (value is 20) | |
*/ | |
private static final int MAX_CONCURRRENT_JOBS = 20; | |
// ------------------------------------------------------------------------ | |
// Members | |
// ------------------------------------------------------------------------ | |
/** | |
* Field fLock. | |
*/ | |
private final ReentrantLock fLock = new ReentrantLock(); | |
/** | |
* Field fRunningJobs. | |
*/ | |
private final AtomicInteger fRunningJobs = new AtomicInteger(0); | |
/** | |
* Field fExceptionError. | |
*/ | |
private Exception fExceptionError; | |
// ------------------------------------------------------------------------ | |
// Methods | |
// ------------------------------------------------------------------------ | |
/** | |
* Method execute. | |
* | |
* @param aEvent | |
* ExecutionEvent | |
* @return Object | |
* @throws ExecutionException | |
* @see org.eclipse.core.commands.IHandler#execute(ExecutionEvent) | |
*/ | |
public Object execute(final ExecutionEvent aEvent) { | |
fExceptionError = null; | |
//Make sure that Reentrant lock is in the proper state | |
if (fLock.isLocked()) { | |
fLock.unlock(); | |
} | |
// Get project to use (use adapters if needed) | |
final ISelection selection = HandlerUtil.getCurrentSelection(aEvent); | |
if (selection instanceof IStructuredSelection) { | |
final Object selectedElement = ((IStructuredSelection) selection).getFirstElement(); | |
IProject project = null; | |
// NOTE: The validity tests are done if the ProjectPropertyTester class | |
if (selectedElement instanceof IProject) { | |
project = (IProject) selectedElement; | |
} else if (R4EUIPlugin.isJDTAvailable() && selectedElement instanceof IJavaProject) { | |
project = ((IJavaProject) selectedElement).getProject(); | |
} else if (R4EUIPlugin.isCDTAvailable() && selectedElement instanceof org.eclipse.cdt.core.model.ICProject) { | |
project = ((org.eclipse.cdt.core.model.ICProject) selectedElement).getProject(); | |
} else if (selectedElement instanceof IPackageFragment || selectedElement instanceof IPackageFragmentRoot) { | |
project = ((IJavaElement) selectedElement).getJavaProject().getProject(); | |
} else if (selectedElement instanceof IFolder) { | |
project = ((IFolder) selectedElement).getProject(); | |
} else if (selectedElement instanceof IAdaptable) { | |
final IAdaptable adaptableProject = (IAdaptable) selectedElement; | |
project = (IProject) adaptableProject.getAdapter(IProject.class); | |
} else { | |
// Should never happen | |
R4EUIPlugin.Ftracer.traceError("No project defined for selection of class " //$NON-NLS-1$ | |
+ ((null != selectedElement) ? selectedElement.getClass() : "")); | |
R4EUIPlugin.getDefault() | |
.logError( | |
"No project defined for selection of class " + ((null != selectedElement) ? selectedElement.getClass() : ""), null); //$NON-NLS-1$ | |
final ErrorDialog dialog = new ErrorDialog(null, R4EUIConstants.DIALOG_TITLE_ERROR, | |
"Find Review Item Error", new Status(IStatus.ERROR, R4EUIPlugin.PLUGIN_ID, 0, | |
"No project defined for selection", null), IStatus.ERROR); | |
dialog.open(); | |
return null; | |
} | |
final ScmConnectorUi uiConnector = R4EUIDialogFactory.getInstance().getScmUiConnector(project); | |
if (null != uiConnector) { | |
R4EUIPlugin.Ftracer.traceDebug("Resolved Scm Ui connector: " + uiConnector); //$NON-NLS-1$ | |
final ChangeSet changeSet = uiConnector.getChangeSet(null, project); | |
createReviewItem(aEvent, changeSet); | |
} else { | |
// We could not find any version control system, thus no items | |
final String strProject = ((null == project) ? "(no project)" : project.getName()); //$NON-NLS-1$ | |
R4EUIPlugin.Ftracer.traceDebug("No Scm Ui connector found for project: " + strProject); //$NON-NLS-1$ | |
final ErrorDialog dialog = new ErrorDialog(null, R4EUIConstants.DIALOG_TITLE_WARNING, | |
"Cannot find new Review Items", new Status(IStatus.WARNING, R4EUIPlugin.PLUGIN_ID, 0, | |
"No SCM Connector detected for Project " + strProject, null), IStatus.WARNING); | |
dialog.open(); | |
} | |
} | |
return null; | |
} | |
/** | |
* Create and serialize the changeset in a Review Item | |
* | |
* @param aChangeSet | |
* ChangeSet | |
* @param aEvent | |
* ExecutionEvent | |
*/ | |
private void createReviewItem(final ExecutionEvent aEvent, final ChangeSet aChangeSet) { | |
if (null == aChangeSet) { | |
R4EUIPlugin.Ftracer.traceInfo("Received null ChangeSet"); //$NON-NLS-1$ | |
return; | |
} | |
final int size = aChangeSet.getChanges().size(); | |
R4EUIPlugin.Ftracer.traceInfo("Received ChangeSet with " + size + " elements"); //$NON-NLS-1$ //$NON-NLS-2$ | |
if (0 == size) { | |
return; // nothing to add | |
} | |
//Check if Review Item already exists | |
final R4EUIReviewBasic uiReview = R4EUIModelController.getActiveReview(); | |
if (null == uiReview) { | |
return; | |
} | |
for (R4EUIReviewItem uiItem : uiReview.getReviewItems()) { | |
if (null != uiItem) { | |
if (aChangeSet.getId().equals(uiItem.getItem().getRepositoryRef())) { | |
//The commit item already exists so ignore command | |
R4EUIPlugin.Ftracer.traceWarning("Review Item already exists. Ignoring"); | |
final ErrorDialog dialog = new ErrorDialog(null, R4EUIConstants.DIALOG_TITLE_WARNING, | |
"Cannot add Review Item", new Status(IStatus.WARNING, R4EUIPlugin.PLUGIN_ID, 0, | |
"Review Item already exists", null), IStatus.WARNING); | |
dialog.open(); | |
return; | |
} | |
} | |
} | |
try { | |
// Get handle to local storage repository | |
final IRFSRegistry localRepository = RFSRegistryFactory.getRegistry(R4EUIModelController.getActiveReview() | |
.getReview()); | |
//Create Synchronized list that will temporarly hold the elements to be added | |
final List<TempFileContext> filesToAddlist = Collections.synchronizedList(new ArrayList<TempFileContext>()); | |
//The Main Job is the parent of all the child jobs that execute the work | |
final Job mainJob = new Job(IMPORTING_FILES_MSG) { | |
@Override | |
public IStatus run(final IProgressMonitor aMonitor) { | |
if (null == aMonitor) { | |
return Status.CANCEL_STATUS; | |
} | |
R4EUIModelController.setJobInProgress(true); //Disable operations on UI | |
aMonitor.beginTask(IMPORTING_FILES_MSG, 3); | |
//First fetch base and target files from remote repository and copy them to the R4E local repository using parallel jobs | |
aMonitor.subTask(FETCHING_FILES_MSG); | |
//Prepare to collect performance trace information (if enabled). | |
Date startImportingTime = null; | |
Date startFetchTime = null; | |
if (Tracer.isInfo()) { | |
startImportingTime = new Date(); | |
startFetchTime = new Date(); | |
} | |
for (final Change change : aChangeSet.getChanges()) { | |
final Job fetchJob = new Job(FETCHING_FILE_MSG) { | |
@Override | |
public boolean belongsTo(Object aFamily) { | |
return FETCH_JOB_FAMILY.equals(aFamily); | |
} | |
@Override | |
public IStatus run(IProgressMonitor aFetchMonitor) { | |
if (null == aFetchMonitor) { | |
return Status.CANCEL_STATUS; | |
} | |
//If the main task is cancelled, abort here | |
if (aMonitor.isCanceled()) { | |
return Status.CANCEL_STATUS; | |
} | |
aFetchMonitor.beginTask(FETCHING_FILE_MSG, 2); | |
try { | |
TempFileContext file = fetchFiles(change, localRepository, aMonitor, aFetchMonitor); | |
filesToAddlist.add(file); | |
aFetchMonitor.done(); | |
return Status.OK_STATUS; | |
} catch (final ReviewsFileStorageException e) { | |
R4EUIPlugin.Ftracer.traceError(R4EUIConstants.EXCEPTION_MSG + e.toString() | |
+ " (" + e.getMessage() //$NON-NLS-1$ | |
+ ")"); //$NON-NLS-1$ | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + e.toString(), e); | |
if (null == fExceptionError) { | |
fExceptionError = e; | |
} | |
aFetchMonitor.done(); | |
return Status.CANCEL_STATUS; | |
} catch (final CoreException e) { | |
if (!e.getMessage().equals(R4EUIConstants.CANCEL_EXCEPTION_MSG)) { | |
R4EUIPlugin.Ftracer.traceError(R4EUIConstants.EXCEPTION_MSG + e.toString() | |
+ " (" + e.getMessage() //$NON-NLS-1$ | |
+ ")"); //$NON-NLS-1$ | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + e.toString(), | |
e); | |
if (null == fExceptionError) { | |
fExceptionError = e; | |
} | |
} | |
aFetchMonitor.done(); | |
return Status.CANCEL_STATUS; | |
} | |
} | |
}; | |
/* Listen to Job's Lifecycle */ | |
fetchJob.addJobChangeListener(new JobChangeAdapter() { | |
/* Count the number of running Jobs for the Rule */ | |
@Override | |
public void running(IJobChangeEvent aEvent) { | |
if (null == aEvent || (null == aEvent.getResult()) | |
|| !aEvent.getResult().equals(Status.CANCEL_STATUS)) { | |
fRunningJobs.getAndIncrement(); | |
} | |
} | |
/* Update Fields when a Job is Done */ | |
@Override | |
public void done(IJobChangeEvent aEvent) { | |
fRunningJobs.decrementAndGet(); | |
} | |
}); | |
/* Apply the internal Rule */ | |
fetchJob.setRule(new JobQueueSchedulingRule()); | |
/* Do not interrupt on any Error */ | |
fetchJob.setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE); | |
fetchJob.setUser(false); | |
fetchJob.schedule(); | |
} | |
try { | |
Job.getJobManager().join(FETCH_JOB_FAMILY, null); | |
} catch (OperationCanceledException ex) { | |
return Status.CANCEL_STATUS; | |
} catch (InterruptedException ex) { | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + ex.toString(), ex); | |
return Status.CANCEL_STATUS; | |
} | |
//If the task is cancelled, abort here | |
if (aMonitor.isCanceled()) { | |
aMonitor.done(); | |
R4EUIModelController.setJobInProgress(false); | |
if (null != fExceptionError) { | |
if (fExceptionError instanceof ReviewsFileStorageException) { | |
UIUtils.displayReviewsFileStorageErrorDialog((ReviewsFileStorageException) fExceptionError); | |
} else if (fExceptionError instanceof CoreException) { | |
UIUtils.displayCoreErrorDialog((CoreException) fExceptionError); | |
} | |
} | |
return Status.CANCEL_STATUS; | |
} | |
aMonitor.worked(1); | |
//Tracing add fetch time | |
if (startFetchTime != null) { | |
R4EUIPlugin.Ftracer.traceInfo("Total time to Import/Push files is: " //$NON-NLS-1$ | |
+ ((new Date()).getTime() - startFetchTime.getTime())); | |
} | |
//Reset Tracing benchmark timer | |
Date startingComputeTime = null; | |
if (Tracer.isInfo()) { | |
startingComputeTime = new Date(); | |
} | |
//Second calculate deltas for all fetched files using parallel jobs (if configured in preferences) | |
if (R4EUIPlugin.getDefault().getPreferenceStore().getBoolean(PreferenceConstants.P_USE_DELTAS)) { | |
aMonitor.subTask(CALCULATE_DELTAS_MSG); | |
for (final TempFileContext file : filesToAddlist) { | |
if (null == file) { | |
continue; | |
} | |
final Job deltaJob = new Job(CALCULATE_DELTAS_MSG) { | |
@Override | |
public boolean belongsTo(Object aFamily) { | |
return DELTA_JOB_FAMILY.equals(aFamily); | |
} | |
@Override | |
public IStatus run(IProgressMonitor aDeltaMonitor) { | |
if (null == aDeltaMonitor) { | |
return Status.CANCEL_STATUS; | |
} | |
aDeltaMonitor.beginTask(CALCULATE_DELTAS_FILE_MSG + file.toString(), 1); | |
try { | |
updateFilesWithDeltas(file); | |
} catch (CoreException e) { | |
R4EUIPlugin.Ftracer.traceError(R4EUIConstants.EXCEPTION_MSG + e.toString() | |
+ " (" + e.getMessage() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + e.toString(), | |
e); | |
} | |
aDeltaMonitor.worked(1); | |
aDeltaMonitor.done(); | |
return Status.OK_STATUS; | |
} | |
}; | |
/* Listen to Job's Lifecycle */ | |
deltaJob.addJobChangeListener(new JobChangeAdapter() { | |
/* Count the number of running Jobs for the Rule */ | |
@Override | |
public void running(IJobChangeEvent aEvent) { | |
if (null == aEvent || (null == aEvent.getResult()) | |
|| !aEvent.getResult().equals(Status.CANCEL_STATUS)) { | |
fRunningJobs.getAndIncrement(); | |
} | |
} | |
/* Update Fields when a Job is Done */ | |
@Override | |
public void done(IJobChangeEvent aEvent) { | |
fRunningJobs.decrementAndGet(); | |
} | |
}); | |
/* Apply the internal Rule */ | |
deltaJob.setRule(new JobQueueSchedulingRule()); | |
/* Do not interrupt on any Error */ | |
deltaJob.setProperty(IProgressConstants.NO_IMMEDIATE_ERROR_PROMPT_PROPERTY, Boolean.TRUE); | |
deltaJob.setUser(false); | |
deltaJob.schedule(); | |
} | |
try { | |
Job.getJobManager().join(DELTA_JOB_FAMILY, null); | |
} catch (OperationCanceledException ex) { | |
return Status.CANCEL_STATUS; | |
} catch (InterruptedException ex) { | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + ex.toString(), ex); | |
return Status.CANCEL_STATUS; | |
} | |
} | |
//If the task is cancelled, exit | |
if (aMonitor.isCanceled()) { | |
aMonitor.done(); | |
R4EUIModelController.setJobInProgress(false); | |
return Status.CANCEL_STATUS; | |
} | |
aMonitor.worked(1); | |
//Tracing add calculate changes time | |
if (startingComputeTime != null) { | |
R4EUIPlugin.Ftracer.traceInfo("Total time to Compute changes is: " //$NON-NLS-1$ | |
+ ((new Date()).getTime() - startingComputeTime.getTime())); | |
} | |
//Reset Tracing benchmark timer | |
Date startUpdatingModel = null; | |
if (Tracer.isInfo()) { | |
startUpdatingModel = new Date(); | |
} | |
//Third add all elements to the UI model | |
aMonitor.subTask(ADD_ELEMENT_MSG); | |
final Job addJob = new Job(ADD_ELEMENT_MSG) { | |
@Override | |
public boolean belongsTo(Object aFamily) { | |
return ADD_JOB_FAMILY.equals(aFamily); | |
} | |
@Override | |
public IStatus run(IProgressMonitor aAddMonitor) { | |
if (null == aAddMonitor) { | |
return Status.CANCEL_STATUS; | |
} | |
try { | |
final R4EUIReviewItem uiReviewItem; | |
if (filesToAddlist.size() > 0) { | |
aAddMonitor.beginTask(ADD_ELEMENT_MSG, filesToAddlist.size() + 1); | |
aAddMonitor.subTask(ADD_REVIEW_ITEM_MSG); | |
uiReviewItem = uiReview.createCommitReviewItem(aChangeSet, null); | |
aAddMonitor.worked(1); | |
//Lock the resource to the user review items to avoid parallel updates from other users | |
Resource resource = uiReviewItem.getItem().eResource(); | |
final Long bookNum = R4EUIModelController.FResourceUpdater.checkOut( | |
uiReviewItem.getItem(), R4EUIModelController.getReviewer()); | |
//Prevent serialization for each individual child element and wait till the end | |
R4EUIModelController.stopSerialization(resource); | |
for (TempFileContext file : filesToAddlist) { | |
addFileToModel(uiReviewItem, file, aAddMonitor); | |
} | |
//Resume serialization | |
R4EUIModelController.resetToDefaultSerialization(); | |
//Check-in to serialise the whole commit element with children | |
R4EUIModelController.FResourceUpdater.checkIn(bookNum); | |
UIUtils.setNavigatorViewFocus(uiReviewItem, 1); | |
//Notify users if need be | |
final List<R4EReviewComponent> addedItems = new ArrayList<R4EReviewComponent>(); | |
addedItems.add(uiReviewItem.getItem()); | |
final R4EReview review = uiReview.getReview(); | |
if (review.getType().equals(R4EReviewType.R4E_REVIEW_TYPE_FORMAL)) { | |
if (((R4EFormalReview) review).getCurrent() | |
.getType() | |
.equals(R4EReviewPhase.R4E_REVIEW_PHASE_PREPARATION)) { | |
MailServicesProxy.sendItemsAddedNotification(addedItems); | |
} | |
} | |
} | |
} catch (CoreException e) { | |
UIUtils.displayCoreErrorDialog(e); | |
} catch (ResourceHandlingException e) { | |
UIUtils.displayResourceErrorDialog(e); | |
} catch (OutOfSyncException e) { | |
UIUtils.displaySyncErrorDialog(e); | |
} finally { | |
//Minimize the possibility to remain with serialization off | |
R4EUIModelController.resetToDefaultSerialization(); | |
} | |
return Status.OK_STATUS; | |
} | |
}; | |
addJob.setUser(false); | |
addJob.schedule(); | |
try { | |
Job.getJobManager().join(ADD_JOB_FAMILY, null); | |
} catch (OperationCanceledException ex) { | |
return Status.CANCEL_STATUS; | |
} catch (InterruptedException ex) { | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + ex.toString(), ex); | |
return Status.CANCEL_STATUS; | |
} | |
//Tracing add updating model time | |
if (startUpdatingModel != null) { | |
Date jobEnd = new Date(); | |
R4EUIPlugin.Ftracer.traceInfo("Total time to update model is: " //$NON-NLS-1$ | |
+ (jobEnd.getTime() - startUpdatingModel.getTime())); | |
} | |
//Tracing add total time | |
if (startImportingTime != null) { | |
Date jobEnd = new Date(); | |
R4EUIPlugin.Ftracer.traceInfo("Total time to fetch files, compute deltas and update model is: " //$NON-NLS-1$ | |
+ (jobEnd.getTime() - startImportingTime.getTime())); | |
} | |
aMonitor.worked(1); | |
aMonitor.done(); | |
R4EUIModelController.setJobInProgress(false); | |
return Status.OK_STATUS; | |
} | |
}; | |
mainJob.setUser(true); | |
mainJob.schedule(); | |
} catch (ReviewsFileStorageException e) { | |
UIUtils.displayReviewsFileStorageErrorDialog(e); | |
} | |
} | |
/** | |
* Method fetchFiles. | |
* | |
* @param aChange | |
* Change | |
* @param aLocalRepository | |
* IRFSRegistry | |
* @param aMainMonitor | |
* IProgressMonitor | |
* @param aSubMonitor | |
* IProgressMonitor | |
* @return TempFileContext | |
* @throws CoreException | |
* @throws ReviewsFileStorageException | |
* @throws SubJobCancelledException | |
* @throws MainJobCancelledException | |
*/ | |
private TempFileContext fetchFiles(final Change aChange, IRFSRegistry aLocalRepository, | |
IProgressMonitor aMainMonitor, IProgressMonitor aSubMonitor) throws ReviewsFileStorageException, | |
CoreException { | |
R4EFileVersion baseLocalVersion = null; | |
R4EFileVersion targetLocalVersion = null; | |
//Get Base artifact | |
final ScmArtifact baseArt = aChange.getBase(); | |
if (null != baseArt) { | |
// Copy to the local repository | |
aSubMonitor.subTask(FETCHING_FILE_MSG + baseArt.getPath() + " (base) from remote repository"); //$NON-NLS-1$ | |
baseLocalVersion = CommandUtils.copyRemoteFileToLocalRepository(fLock, aLocalRepository, baseArt, | |
aMainMonitor); | |
} | |
aSubMonitor.worked(1); | |
//Get Target artifact | |
final ScmArtifact targetArt = aChange.getTarget(); | |
if (null != targetArt) { | |
aSubMonitor.subTask(FETCHING_FILE_MSG + targetArt.getPath() + " (target) from remote repository"); //$NON-NLS-1$ | |
targetLocalVersion = CommandUtils.copyRemoteFileToLocalRepository(fLock, aLocalRepository, targetArt, | |
aMainMonitor); | |
} | |
aSubMonitor.worked(1); | |
// Add File Context to the list to be added | |
return new TempFileContext(aLocalRepository, baseLocalVersion, targetLocalVersion, | |
CommandUtils.adaptType(aChange.getChangeType())); | |
} | |
/** | |
* Method updateFilesWithDeltas. | |
* | |
* @param aFile | |
* TempFileContext | |
* @throws CoreException | |
*/ | |
private void updateFilesWithDeltas(final TempFileContext aFile) throws CoreException { | |
//Find all differecences between Base and Target files | |
final R4ECompareEditorInput input = CommandUtils.createCompareEditorInput(aFile.getBase(), aFile.getTarget()); | |
input.prepareCompareInputNoEditor(); | |
final DiffUtils diffUtils = new DiffUtils(); | |
final List<Diff> diffs; | |
fLock.lock(); | |
try { | |
diffs = diffUtils.doDiff(false, true, input); | |
} finally { | |
fLock.unlock(); | |
} | |
//Add Deltas from the list of differences | |
for (Diff diff : diffs) { | |
IR4EUIPosition position = CommandUtils.getPosition(diff.getPosition(R4EUIConstants.LEFT_CONTRIBUTOR) | |
.getOffset(), diff.getPosition(R4EUIConstants.LEFT_CONTRIBUTOR).getLength(), | |
diff.getDocument(R4EUIConstants.LEFT_CONTRIBUTOR)); | |
if ((null == position) || (RangeDifference.NOCHANGE == diff.getKind())) { | |
continue; //Cannot resolve position for this delta or no change | |
} | |
aFile.getPositions().add(position); | |
} | |
} | |
/** | |
* Method addFileToModel. | |
* | |
* @param aUiReviewItem | |
* R4EUIReviewItem | |
* @param aFile | |
* TempFileContext | |
* @param aMonitor | |
* IProgressMonitor | |
*/ | |
private void addFileToModel(R4EUIReviewItem aUiReviewItem, TempFileContext aFile, IProgressMonitor aMonitor) { | |
try { | |
String addedFilename; | |
if (null != aFile.getTarget()) { | |
addedFilename = aFile.getTarget().getName(); | |
} else if (null != aFile.getBase()) { | |
addedFilename = aFile.getBase().getName(); | |
} else { | |
addedFilename = ""; //Should never happen //$NON-NLS-1$ | |
} | |
aMonitor.subTask("Adding file " + addedFilename + " to R4E model"); //$NON-NLS-1$//$NON-NLS-2$ | |
final R4EUIFileContext uiFileContext = aUiReviewItem.createFileContext(aFile.getBase(), aFile.getTarget(), | |
aFile.getType()); | |
for (IR4EUIPosition position : aFile.getPositions()) { | |
//Lazily create the Delta container if not already done | |
R4EUIDeltaContainer deltaContainer = (R4EUIDeltaContainer) uiFileContext.getContentsContainerElement(); | |
deltaContainer.createDelta((R4EUITextPosition) position); | |
} | |
} catch (OutOfSyncException e) { | |
R4EUIPlugin.Ftracer.traceError(R4EUIConstants.EXCEPTION_MSG + e.toString() + " (" + e.getMessage() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + e.toString(), e); | |
} catch (ResourceHandlingException e) { | |
R4EUIPlugin.Ftracer.traceError(R4EUIConstants.EXCEPTION_MSG + e.toString() + " (" + e.getMessage() + ")"); //$NON-NLS-1$ //$NON-NLS-2$ | |
R4EUIPlugin.getDefault().logError(R4EUIConstants.EXCEPTION_MSG + e.toString(), e); | |
} | |
aMonitor.worked(1); | |
} | |
/** | |
* Class TempFileContext internal class that aggregates info needed to import files into R4E | |
* | |
* @author Sebastien Dubois | |
*/ | |
private static class TempFileContext { | |
/** | |
* Field base. | |
*/ | |
private final R4EFileVersion fBase; | |
/** | |
* Field target. | |
*/ | |
private final R4EFileVersion fTarget; | |
/** | |
* Field type. | |
*/ | |
private final R4EContextType fType; | |
/** | |
* Field positions. | |
*/ | |
private final List<IR4EUIPosition> fPositions; | |
/** | |
* Constructor for TempFileContext. | |
* | |
* @param aRepository | |
* IRFSRegistry | |
* @param aBase | |
* R4EFileVersion | |
* @param aTarget | |
* R4EFileVersion | |
* @param aType | |
* R4EContextType | |
*/ | |
TempFileContext(IRFSRegistry aRepository, R4EFileVersion aBase, R4EFileVersion aTarget, R4EContextType aType) { | |
fBase = aBase; | |
//Add IFileRevision info | |
if ((null != fBase) && (null != aRepository)) { | |
try { | |
final IFileRevision fileRev = aRepository.getIFileRevision(null, fBase); | |
fBase.setFileRevision(fileRev); | |
} catch (ReviewsFileStorageException e) { | |
R4EUIPlugin.Ftracer.traceInfo(R4EUIConstants.EXCEPTION_MSG + e.toString() + " (" + e.getMessage() //$NON-NLS-1$ | |
+ ")"); //$NON-NLS-1$ | |
} | |
} | |
fTarget = aTarget; | |
//Add IFileRevision info | |
if ((null != fTarget) && (null != aRepository)) { | |
try { | |
final IFileRevision fileRev = aRepository.getIFileRevision(null, fTarget); | |
fTarget.setFileRevision(fileRev); | |
} catch (ReviewsFileStorageException e) { | |
R4EUIPlugin.Ftracer.traceInfo(R4EUIConstants.EXCEPTION_MSG + e.toString() + " (" + e.getMessage() //$NON-NLS-1$ | |
+ ")"); //$NON-NLS-1$ | |
} | |
} | |
fType = aType; | |
fPositions = new ArrayList<IR4EUIPosition>(); | |
} | |
/** | |
* Method getBase. | |
* | |
* @return R4EFileVersion | |
*/ | |
public R4EFileVersion getBase() { | |
return fBase; | |
} | |
/** | |
* Method getTarget. | |
* | |
* @return R4EFileVersion | |
*/ | |
public R4EFileVersion getTarget() { | |
return fTarget; | |
} | |
/** | |
* Method getType. | |
* | |
* @return R4EContextType | |
*/ | |
public R4EContextType getType() { | |
return fType; | |
} | |
/** | |
* Method getPositions. | |
* | |
* @return List<IR4EUIPosition> | |
*/ | |
public List<IR4EUIPosition> getPositions() { | |
return fPositions; | |
} | |
} | |
/** | |
* Class JobQueueSchedulingRule Job scheduling rule that only allows a certain number of concurrent Jobs | |
* | |
* @author Sebastien Dubois | |
*/ | |
class JobQueueSchedulingRule implements ISchedulingRule { | |
/** | |
* Method contains. | |
* | |
* @param aRule | |
* - ISchedulingRule | |
* @return boolean | |
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#contains(ISchedulingRule) | |
*/ | |
public boolean contains(ISchedulingRule aRule) { | |
return aRule.equals(this); | |
} | |
/** | |
* Method isConflicting. | |
* | |
* @param aRule | |
* - ISchedulingRule | |
* @return boolean | |
* @see org.eclipse.core.runtime.jobs.ISchedulingRule#isConflicting(ISchedulingRule) | |
*/ | |
public boolean isConflicting(ISchedulingRule aRule) { | |
if (aRule.equals(this)) { | |
return true; | |
} | |
if (!(aRule instanceof JobQueueSchedulingRule)) { | |
return false; | |
} | |
/* Conflict if number of running Jobs already greater maximum */ | |
return FindReviewItemsHandler.this.fRunningJobs.intValue() >= MAX_CONCURRRENT_JOBS; | |
} | |
} | |
} |