/*
* JBoss, Home of Professional Open Source.
*
* See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing.
*
* See the AUTHORS.txt file distributed with this work for a full listing of individual contributors.
*/
package org.teiid.designer.ui.refactor.move;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.ltk.core.refactoring.Change;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.TextFileChange;
import org.eclipse.ltk.core.refactoring.resource.MoveResourceChange;
import org.teiid.designer.core.refactor.IRefactorModelHandler.RefactorType;
import org.teiid.designer.core.refactor.PathPair;
import org.teiid.designer.core.refactor.RelatedResourceFinder.Relationship;
import org.teiid.designer.core.workspace.ModelUtil;
import org.teiid.designer.ui.UiConstants;
import org.teiid.designer.ui.refactor.AbstractResourcesRefactoring;
import org.teiid.designer.ui.refactor.RefactorResourcesUtils;
import org.teiid.designer.ui.refactor.RefactorResourcesUtils.AbstractResourceCallback;
import org.teiid.designer.ui.refactor.RefactorResourcesUtils.IResourceCallback;
/**
*
*/
public class MoveResourcesRefactoring extends AbstractResourcesRefactoring {
private class RelatedResourceCallback extends VdbResourceCallback {
private final Set<PathPair> pathPairs;
private final Set<IResource> history = new HashSet<IResource>();
/**
* @param pathPairs
*/
public RelatedResourceCallback(Set<PathPair> pathPairs) {
this.pathPairs = pathPairs;
}
@Override
public void checkValidFile(IFile relatedFile, RefactoringStatus status) {
checkResource(relatedFile, new NullProgressMonitor(), status);
}
@Override
public void indexFile(IResource resource, IFile relatedFile, RefactoringStatus status) throws Exception {
RefactorResourcesUtils.unloadModelResource(relatedFile);
if (history.contains(relatedFile)) {
/*
* This file has been processed before implying that it is related
* to more than one target resource.
*
* Since pathpairs are global to all resources there is
* no point in processing the related file more than once.
*/
return;
}
// Add the related file to the history to avoid processing it again
history.add(relatedFile);
if (getResourcesAndChildren(status).contains(relatedFile)) {
/*
* Changes are not applicable as the related file is moving
* to the new destination as well
*/
return;
}
if (pathPairs == null || pathPairs.isEmpty())
return;
IPath relatedFilePath = ModelUtil.getLocation(relatedFile).makeAbsolute();
IPath relatedParentPath = relatedFilePath.removeLastSegments(1);
// Convert the path pair to a pair of relative paths
Set<PathPair> relativePathPairs = new HashSet<PathPair>();
for (PathPair absPathPair : pathPairs) {
relativePathPairs.add(RefactorResourcesUtils.getRelativePath(relatedParentPath.toOSString(), absPathPair));
}
TextFileChange textFileChange = RefactorResourcesUtils.calculateTextChanges(relatedFile, relativePathPairs);
for( PathPair pair : relativePathPairs ) {
RefactorResourcesUtils.calculateModelImportsElementLChanges(relatedFile, pair, textFileChange);
}
if (addTextChange(relatedFile, textFileChange)) {
// Calculate the effect on any vdbs containing this modified related file
RefactorResourcesUtils.calculateRelatedVdbResources(relatedFile, status, this);
}
}
}
private IContainer destination;
/**
* @param selectedResources
*/
public MoveResourcesRefactoring(final List<IResource> selectedResources) {
super(RefactorResourcesUtils.getString("MoveRefactoring.title"), selectedResources); //$NON-NLS-1$
}
/**
* @return the destination container
*/
public IContainer getDestination() {
return destination;
}
/**
* Set the destination
*
* @param destination
*/
public void setDestination(IContainer destination) {
this.destination = destination;
}
@Override
protected void checkResource(IResource resource, IProgressMonitor progressMonitor, RefactoringStatus status) {
String readOnlyStatusMsg;
if (getResources().contains(resource)) {
readOnlyStatusMsg = RefactorResourcesUtils.getString("ResourcesRefactoring.readOnlyResourceError", //$NON-NLS-1$
resource.getName());
} else {
readOnlyStatusMsg = RefactorResourcesUtils.getString("ResourcesRefactoring.readOnlyRelatedResourceError", //$NON-NLS-1$
resource.getName());
}
RefactorResourcesUtils.checkResourceExists(resource, status);
if (!status.isOK()) return;
RefactorResourcesUtils.checkResourceSynched(resource, status);
if (!status.isOK()) return;
RefactorResourcesUtils.checkResourceWritable(resource, status, IStatus.ERROR, readOnlyStatusMsg);
if (!status.isOK()) return;
RefactorResourcesUtils.checkResourceIsNotProject(resource, status);
if (!status.isOK()) return;
RefactorResourcesUtils.checkExtensionManager(resource, RefactorType.MOVE, progressMonitor, status);
if (!status.isOK()) return;
RefactorResourcesUtils.checkModelResourceWritable(resource, status, IStatus.ERROR, readOnlyStatusMsg);
if (!status.isOK()) return;
RefactorResourcesUtils.checkSavedResource(resource, status);
if (!status.isOK()) return;
RefactorResourcesUtils.checkOpenEditors(resource, status);
}
@Override
public RefactoringStatus checkInitialConditions(final IProgressMonitor progressMonitor) throws OperationCanceledException {
RefactoringStatus status = new RefactoringStatus();
try {
progressMonitor.beginTask(RefactorResourcesUtils.getString("MoveRefactoring.initialConditions"), 1); //$NON-NLS-1$
for (IResource resource : getResources()) {
checkResource(resource, progressMonitor, status);
if (! status.isOK()) break;
// Check validity of related resources
IResourceCallback callback = new AbstractResourceCallback() {
@Override
public void checkValidFile(IFile relatedFile, RefactoringStatus validityStatus) {
checkResource(relatedFile, progressMonitor, validityStatus);
}
};
RefactorResourcesUtils.calculateRelatedResources(resource, status, callback, Relationship.DEPENDENT);
}
} finally {
progressMonitor.done();
}
return status;
}
@Override
public RefactoringStatus checkFinalConditions(IProgressMonitor progressMonitor) throws OperationCanceledException {
/* Clear changes in case we are going back then forward in the wizard */
clearChanges();
RefactoringStatus status = new RefactoringStatus();
try {
String destinationPath = ModelUtil.getLocation(destination).makeAbsolute().toOSString();
progressMonitor.beginTask(RefactorResourcesUtils.getString("MoveRefactoring.finalConditions"), 2); //$NON-NLS-1$
Set<PathPair> pathPairs = RefactorResourcesUtils.calculateResourceMoves(getResources(), destinationPath, RefactorResourcesUtils.Option.EXCLUDE_FOLDERS);
RelatedResourceCallback relatedResourceCallback = new RelatedResourceCallback(pathPairs);
for (IResource resource : getResources()) {
// Find the resource's related resources and determine their changes
RefactorResourcesUtils.calculateRelatedResources(resource, status, relatedResourceCallback, Relationship.DEPENDENT);
// Find the resource's imports as they need to be updated due to the resource move
if (ModelUtil.isModelFile(resource)) {
IFile file = (IFile) resource;
Set<PathPair> importPathPairs = RefactorResourcesUtils.calculateImportChanges(file, destinationPath, getResourcesAndChildren(status));
TextFileChange textFileChange = RefactorResourcesUtils.calculateTextChanges(file, importPathPairs);
for( PathPair pair : importPathPairs ) {
RefactorResourcesUtils.calculateModelImportsElementLChanges(file, pair, textFileChange);
}
if (addTextChange(file, textFileChange)) {
// Calculate the effect on any vdbs containing this modified related file
RefactorResourcesUtils.calculateRelatedVdbResources(file, status, new VdbResourceCallback());
}
}
addChange(resource, new MoveResourceChange(resource, destination));
}
} catch (Exception ex) {
UiConstants.Util.log(ex);
status.merge(RefactoringStatus.createFatalErrorStatus(ex.getMessage()));
return status;
}
finally {
progressMonitor.done();
}
return status;
}
@Override
public Change createChange(IProgressMonitor progressMonitor) throws OperationCanceledException, CoreException {
try {
progressMonitor.beginTask(RefactorResourcesUtils.getString("MoveRefactoring.creatingChange"), 1); //$NON-NLS-1$
CompositeChange change = new MoveResourcesCompositeChange( getName(),
getChanges().toArray(new Change[0]),
destination,
getResources());
return change;
} catch (Exception ex) {
throw new CoreException(new Status(IStatus.ERROR, MoveResourcesDescriptor.REFACTORING_ID, ex.getMessage()));
} finally {
progressMonitor.done();
}
}
}