blob: ea18ad69d20fcb48b1017f0b228e8d2b570b830a [file] [log] [blame]
package org.eclipse.jdt.internal.core;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import java.io.InputStream;
/**
* Defines behavior common to all Java Model operations
*/
public abstract class JavaModelOperation implements IWorkspaceRunnable, IProgressMonitor {
/**
* The elements this operation operates on,
* or <code>null</code> if this operation
* does not operate on specific elements.
*/
protected IJavaElement[] fElementsToProcess;
/**
* The parent elements this operation operates with
* or <code>null</code> if this operation
* does not operate with specific parent elements.
*/
protected IJavaElement[] fParentElements;
/**
* An empty collection of <code>IJavaElement</code>s - the common
* empty result if no elements are created, or if this
* operation is not actually executed.
*/
protected static IJavaElement[] fgEmptyResult= new IJavaElement[] {};
/**
* Collection of <code>IJavaElementDelta</code>s created by this operation.
* This collection starts out <code>null</code> and becomes an
* array of <code>IJavaElementDelta</code>s if the operation creates any
* deltas. This collection is registered with the Java Model notification
* manager if the operation completes successfully.
*/
protected IJavaElementDelta[] fDeltas= null;
/**
* The elements created by this operation - empty
* until the operation actually creates elements.
*/
protected IJavaElement[] fResultElements= fgEmptyResult;
/**
* The progress monitor passed into this operation
*/
protected IProgressMonitor fMonitor= null;
/**
* A flag indicating whether this operation is nested.
*/
protected boolean fNested = false;
/**
* Conflict resolution policy - by default do not force (fail on a conflict).
*/
protected boolean fForce= false;
/**
* A common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement[] elements) {
fElementsToProcess = elements;
}
/**
* Common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements) {
fElementsToProcess = elementsToProcess;
fParentElements= parentElements;
}
/**
* A common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement[] elementsToProcess, IJavaElement[] parentElements, boolean force) {
fElementsToProcess = elementsToProcess;
fParentElements= parentElements;
fForce= force;
}
/**
* A common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement[] elements, boolean force) {
fElementsToProcess = elements;
fForce= force;
}
/**
* Common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement element) {
fElementsToProcess = new IJavaElement[]{element};
}
/**
* A common constructor for all Java Model operations.
*/
protected JavaModelOperation(IJavaElement element, boolean force) {
fElementsToProcess = new IJavaElement[]{element};
fForce= force;
}
/**
* Adds the given delta to the collection of deltas
* that this operation has created. These deltas are
* automatically registered with the Java Model Manager
* when the operation completes.
*/
protected void addDelta(IJavaElementDelta delta) {
if (fDeltas == null) {
fDeltas= new IJavaElementDelta[] {delta};
} else {
IJavaElementDelta[] copy= new IJavaElementDelta[fDeltas.length + 1];
System.arraycopy(fDeltas, 0, copy, 0, fDeltas.length);
copy[fDeltas.length]= delta;
fDeltas= copy;
}
}
/**
* @see IProgressMonitor
*/
public void beginTask(String name, int totalWork) {
if (fMonitor != null) {
fMonitor.beginTask(name, totalWork);
}
}
/**
* Checks with the progress monitor to see whether this operation
* should be canceled. An operation should regularly call this method
* during its operation so that the user can cancel it.
*
* @exception OperationCanceledException if cancelling the operation has been requested
* @see IProgressMonitor#isCanceled
*/
protected void checkCanceled() {
if (isCanceled()) {
throw new OperationCanceledException(Util.bind("operation.cancelled")); //$NON-NLS-1$
}
}
/**
* Common code used to verify the elements this operation is processing.
* @see JavaModelOperation#verify()
*/
protected IJavaModelStatus commonVerify() {
if (fElementsToProcess == null || fElementsToProcess.length == 0) {
return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
}
for (int i = 0; i < fElementsToProcess.length; i++) {
if (fElementsToProcess[i] == null) {
return new JavaModelStatus(IJavaModelStatusConstants.NO_ELEMENTS_TO_PROCESS);
}
}
return JavaModelStatus.VERIFIED_OK;
}
/**
* Convenience method to copy resources
*/
protected void copyResources(IResource[] resources, IPath destinationPath) throws JavaModelException {
IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
IWorkspace workspace = resources[0].getWorkspace();
try {
workspace.copy(resources, destinationPath, false, subProgressMonitor);
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Convenience method to create a file
*/
protected void createFile(IContainer folder, String name, InputStream contents, boolean force) throws JavaModelException {
IFile file= folder.getFile(new Path(name));
try {
file.create(contents, force, getSubProgressMonitor(1));
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Convenience method to create a folder
*/
protected void createFolder(IContainer parentFolder, String name, boolean force) throws JavaModelException {
IFolder folder= parentFolder.getFolder(new Path(name));
try {
// we should use true to create the file locally. Only VCM should use tru/false
folder.create(force, true, getSubProgressMonitor(1));
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Convenience method to delete an empty package fragment
*/
protected void deleteEmptyPackageFragment(
IPackageFragment fragment,
boolean force)
throws JavaModelException {
IContainer resource = (IContainer) fragment.getCorrespondingResource();
IResource rootResource = fragment.getParent().getUnderlyingResource();
try {
resource.delete(force, getSubProgressMonitor(1));
while (resource instanceof IFolder) {
// deleting a package: delete the parent if it is empty (eg. deleting x.y where folder x doesn't have resources but y)
// without deleting the package fragment root
resource = resource.getParent();
if (!resource.equals(rootResource) && resource.members().length == 0) {
resource.delete(force, getSubProgressMonitor(1));
}
}
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Convenience method to delete a resource
*/
protected void deleteResource(IResource resource, boolean force) throws JavaModelException {
try {
resource.delete(force, getSubProgressMonitor(1));
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Convenience method to delete resources
*/
protected void deleteResources(IResource[] resources, boolean force) throws JavaModelException {
if (resources == null || resources.length == 0) return;
IProgressMonitor subProgressMonitor = getSubProgressMonitor(resources.length);
IWorkspace workspace = resources[0].getWorkspace();
try {
workspace.delete(resources, force, subProgressMonitor);
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* @see IProgressMonitor
*/
public void done() {
if (fMonitor != null) {
fMonitor.done();
}
}
/**
* Verifies the operation can proceed and executes the operation.
* Subclasses should override <code>#verify</code> and
* <code>executeOperation</code> to implement the specific operation behavior.
*
* @exception JavaModelException The operation has failed.
*/
protected void execute() throws JavaModelException {
IJavaModelStatus status= verify();
if (status.isOK()) {
executeOperation();
} else {
throw new JavaModelException(status);
}
}
/**
* Convenience method to run an operation within this operation
*/
public void executeNestedOperation(JavaModelOperation operation, int subWorkAmount) throws JavaModelException {
IProgressMonitor subProgressMonitor = getSubProgressMonitor(subWorkAmount);
// fix for 1FW7IKC, part (1)
try {
operation.setNested(true);
operation.run(subProgressMonitor);
//accumulate the nested operation deltas
for (int i = 0; i < operation.fDeltas.length; i++) {
addDelta(operation.fDeltas[i]);
}
} catch (CoreException ce) {
if (ce instanceof JavaModelException) {
throw (JavaModelException)ce;
} else {
// translate the core exception to a java model exception
if (ce.getStatus().getCode() == IResourceStatus.OPERATION_FAILED) {
Throwable e = ce.getStatus().getException();
if (e instanceof JavaModelException) {
throw (JavaModelException) e;
}
}
throw new JavaModelException(ce);
}
}
}
/**
* Performs the operation specific behavior. Subclasses must override.
*/
protected abstract void executeOperation() throws JavaModelException;
/**
* Returns the compilation unit the given element is contained in,
* or the element itself (if it is a compilation unit),
* otherwise <code>null</code>.
*/
protected ICompilationUnit getCompilationUnitFor(IJavaElement element) {
return ((JavaElement)element).getCompilationUnit();
}
/**
* Returns the elements to which this operation applies,
* or <code>null</code> if not applicable.
*/
protected IJavaElement[] getElementsToProcess() {
return fElementsToProcess;
}
/**
* Returns the element to which this operation applies,
* or <code>null</code> if not applicable.
*/
protected IJavaElement getElementToProcess() {
if (fElementsToProcess == null || fElementsToProcess.length == 0) {
return null;
}
return fElementsToProcess[0];
}
/**
* Returns the Java Model this operation is operating in.
*/
public IJavaModel getJavaModel() {
if (fElementsToProcess == null || fElementsToProcess.length == 0) {
return getParentElement().getJavaModel();
} else {
return fElementsToProcess[0].getJavaModel();
}
}
/**
* Returns the parent element to which this operation applies,
* or <code>null</code> if not applicable.
*/
protected IJavaElement getParentElement() {
if (fParentElements == null || fParentElements.length == 0) {
return null;
}
return fParentElements[0];
}
/**
* Returns the parent elements to which this operation applies,
* or <code>null</code> if not applicable.
*/
protected IJavaElement[] getParentElements() {
return fParentElements;
}
/**
* Returns the elements created by this operation.
*/
public IJavaElement[] getResultElements() {
return fResultElements;
}
/**
* Creates and returns a subprogress monitor if appropriate.
*/
protected IProgressMonitor getSubProgressMonitor(int workAmount) {
IProgressMonitor sub = null;
if (fMonitor != null) {
sub = new SubProgressMonitor(fMonitor, workAmount, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
}
return sub;
}
/**
* Returns the <code>IWorkspace</code> this operation is working in, or
* <code>null</code> if this operation has no elements to process.
*/
protected IWorkspace getWorkspace() {
if (fElementsToProcess != null && fElementsToProcess.length > 0) {
IJavaProject project = fElementsToProcess[0].getJavaProject();
if (project != null) {
return project.getJavaModel().getWorkspace();
}
}
return null;
}
public void internalWorked(double work) {
if (fMonitor != null) {
fMonitor.internalWorked(work);
}
}
/**
* @see IProgressMonitor
*/
public boolean isCanceled() {
if (fMonitor != null) {
return fMonitor.isCanceled();
}
return false;
}
/**
* Returns <code>true</code> if this operation performs no resource modifications,
* otherwise <code>false</code>. Subclasses must override.
*/
public boolean isReadOnly() {
return false;
}
/**
* Traverses the deltas for an working copies and makes them
* consistent.
*/
protected void makeWorkingCopiesConsistent(IJavaElementDelta[] deltas) {
for (int i= 0; i < deltas.length; i++) {
walkDeltaMakingWorkingCopiesConsistent(deltas[i]);
}
}
/**
* Convenience method to move resources
*/
protected void moveResources(IResource[] resources, IPath destinationPath) throws JavaModelException {
IProgressMonitor subProgressMonitor = null;
if (fMonitor != null) {
subProgressMonitor = new SubProgressMonitor(fMonitor, resources.length, SubProgressMonitor.PREPEND_MAIN_LABEL_TO_SUBTASK);
}
IWorkspace workspace = resources[0].getWorkspace();
try {
workspace.move(resources, destinationPath, false, subProgressMonitor);
} catch (CoreException e) {
throw new JavaModelException(e);
}
}
/**
* Creates and returns a new <code>IJavaElementDelta</code>
* on the Java Model.
*/
public JavaElementDelta newJavaElementDelta() {
return new JavaElementDelta(getJavaModel());
}
/**
* Registers any deltas this operation created, with the
* Java Model manager.
*/
protected void registerDeltas() {
if (fDeltas != null && !fNested) {
// hook to ensure working copies remain consistent
makeWorkingCopiesConsistent(fDeltas);
JavaModelManager manager= (JavaModelManager)JavaModelManager.getJavaModelManager();
for (int i= 0; i < fDeltas.length; i++) {
manager.registerJavaModelDelta(fDeltas[i]);
}
}
}
/**
* Main entry point for Java Model operations. Executes this operation
* and registers any deltas created.
*
* @see IWorkspaceRunnable
* @exception CoreException if the operation fails
*/
public void run(IProgressMonitor monitor) throws CoreException {
try {
fMonitor = monitor;
execute();
} finally {
registerDeltas();
}
}
/**
* @see IProgressMonitor
*/
public void setCanceled(boolean b) {
if (fMonitor != null) {
fMonitor.setCanceled(b);
}
}
/**
* Sets whether this operation is nested or not.
* @see CreateElementInCUOperation#checkCanceled
*/
protected void setNested(boolean nested) {
fNested = nested;
}
/**
* @see IProgressMonitor
*/
public void setTaskName(String name) {
if (fMonitor != null) {
fMonitor.setTaskName(name);
}
}
/**
* @see IProgressMonitor
*/
public void subTask(String name) {
if (fMonitor != null) {
fMonitor.subTask(name);
}
}
/**
* Returns a status indicating if there is any known reason
* this operation will fail. Operations are verified before they
* are run.
*
* Subclasses must override if they have any conditions to verify
* before this operation executes.
*
* @see IJavaModelStatus
*/
protected IJavaModelStatus verify() {
return commonVerify();
}
/**
* Traverses the delta making any working copies consistent
*/
protected void walkDeltaMakingWorkingCopiesConsistent(IJavaElementDelta delta) {
if (delta.getElement().getElementType() == IJavaElement.COMPILATION_UNIT) {
ICompilationUnit unit = (ICompilationUnit) delta.getElement();
if (unit.isWorkingCopy()) {
try {
unit.makeConsistent(null);
} catch (JavaModelException e) {
}
}
} else {
IJavaElementDelta[] deltas = delta.getAffectedChildren();
for (int i = 0; i < deltas.length; i++) {
walkDeltaMakingWorkingCopiesConsistent(deltas[i]);
}
}
}
/**
* @see IProgressMonitor
*/
public void worked(int work) {
if (fMonitor != null) {
fMonitor.worked(work);
checkCanceled();
}
}
}