Copyright (c) 2007, 2018 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation
/******************************************************************************* * Copyright (c) 2007, 2018 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/
package org.eclipse.ltk.core.refactoring.resource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBuffer; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IDocumentExtension4; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.internal.core.refactoring.BasicElementLabels; import org.eclipse.ltk.internal.core.refactoring.Messages; import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
Abstract change for resource based changes. The change controls the resource time stamp and read only state of the resource and makes sure it is not changed before executing the change.
Since:3.4
/** * Abstract change for resource based changes. The change controls the resource time stamp * and read only state of the resource and makes sure it is not changed before executing the change. * * @since 3.4 */
public abstract class ResourceChange extends Change {
The default validation method. It tests the modified element for existence and makes sure it has not been modified since the change has been created.
/** * The default validation method. It tests the modified element for existence and makes sure it has not been modified * since the change has been created. */
public static final int VALIDATE_DEFAULT= 0;
The 'not read only' validation method performs the default validations (see VALIDATE_DEFAULT) and additionally ensures that the element is not read only.
/** * The 'not read only' validation method performs the default validations (see {@link #VALIDATE_DEFAULT}) and additionally ensures that the element * is not read only. */
public static final int VALIDATE_NOT_READ_ONLY= 1 << 0;
The 'not dirty' validation method performs the default validations (see VALIDATE_DEFAULT) and additionally ensures that the element does not contain unsaved modifications.
/** * The 'not dirty' validation method performs the default validations (see {@link #VALIDATE_DEFAULT}) and additionally ensures that the element * does not contain unsaved modifications. */
public static final int VALIDATE_NOT_DIRTY= 1 << 1;
The 'save if dirty' validation method performs the default validations (see VALIDATE_DEFAULT) and will save all unsaved modifications to the resource.
/** * The 'save if dirty' validation method performs the default validations (see {@link #VALIDATE_DEFAULT}) and will * save all unsaved modifications to the resource. */
public static final int SAVE_IF_DIRTY= 1 << 2; private long fModificationStamp; private boolean fReadOnly; private int fValidationMethod;
Creates the resource change. The modification state will be
/** * Creates the resource change. The modification state will be */
public ResourceChange() { fModificationStamp= IResource.NULL_STAMP; fReadOnly= false; fValidationMethod= VALIDATE_DEFAULT; }
Returns the resource of this change.
Returns:the resource of this change
/** * Returns the resource of this change. * * @return the resource of this change */
protected abstract IResource getModifiedResource(); @Override public void initializeValidationData(IProgressMonitor pm) { IResource resource= getModifiedResource(); if (resource != null) { fModificationStamp= getModificationStamp(resource); fReadOnly= Resources.isReadOnly(resource); } }
Sets the validation methods used when the current resource is validated in isValid(IProgressMonitor).

By default the validation method is VALIDATE_DEFAULT. Change implementors can add VALIDATE_NOT_DIRTY, VALIDATE_NOT_READ_ONLY or SAVE_IF_DIRTY.

Params:
/** * Sets the validation methods used when the current resource is validated in {@link #isValid(IProgressMonitor)}. * <p> * By default the validation method is {@link #VALIDATE_DEFAULT}. Change implementors can add {@link #VALIDATE_NOT_DIRTY}, * {@link #VALIDATE_NOT_READ_ONLY} or {@link #SAVE_IF_DIRTY}. * </p> * * @param validationMethod the validation method used in {@link #isValid(IProgressMonitor)}. * Supported validation methods currently are: * <ul><li>{@link #VALIDATE_DEFAULT}</li> * <li>{@link #VALIDATE_NOT_DIRTY}</li> * <li>{@link #VALIDATE_NOT_READ_ONLY}</li> * <li>{@link #SAVE_IF_DIRTY}</li> * </ul> * or combinations of these variables. */
public void setValidationMethod(int validationMethod) { fValidationMethod= validationMethod; }
This implementation of Change.isValid(IProgressMonitor) tests the modified resource using the validation method specified by setValidationMethod(int).
/** * This implementation of {@link Change#isValid(IProgressMonitor)} tests the modified resource using the validation method * specified by {@link #setValidationMethod(int)}. */
@Override public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException { pm.beginTask("", 2); //$NON-NLS-1$ try { RefactoringStatus result= new RefactoringStatus(); IResource resource= getModifiedResource(); checkExistence(result, resource); if (result.hasFatalError()) return result; if (fValidationMethod == VALIDATE_DEFAULT) return result; ValidationState state= new ValidationState(resource); state.checkModificationStamp(result, fModificationStamp); if (result.hasFatalError()) return result; state.checkSameReadOnly(result, fReadOnly); if (result.hasFatalError()) return result; if ((fValidationMethod & VALIDATE_NOT_READ_ONLY) != 0) { state.checkReadOnly(result); if (result.hasFatalError()) return result; } if ((fValidationMethod & SAVE_IF_DIRTY) != 0) { state.saveIfDirty(result, fModificationStamp, new SubProgressMonitor(pm, 1)); } if ((fValidationMethod & VALIDATE_NOT_DIRTY) != 0) { state.checkDirty(result); } return result; } finally { pm.done(); } }
Utility method to validate a resource to be modified.
Params:
/** * Utility method to validate a resource to be modified. * * @param result the status where the result will be added to * @param resource the resource to validate * @param validationMethod the validation method used in {@link #isValid(IProgressMonitor)}. * Supported validation methods currently are: * <ul><li>{@link #VALIDATE_DEFAULT}</li> * <li>{@link #VALIDATE_NOT_DIRTY}</li> * <li>{@link #VALIDATE_NOT_READ_ONLY}</li> * <li>{@link #SAVE_IF_DIRTY}</li> * </ul> * or combinations of these methods. */
protected static void checkIfModifiable(RefactoringStatus result, IResource resource, int validationMethod) { checkExistence(result, resource); if (result.hasFatalError()) return; if (validationMethod == VALIDATE_DEFAULT) return; ValidationState state= new ValidationState(resource); if ((validationMethod & VALIDATE_NOT_READ_ONLY) != 0) { state.checkReadOnly(result); if (result.hasFatalError()) return; } if ((validationMethod & VALIDATE_NOT_DIRTY) != 0) { state.checkDirty(result); } } private static void checkExistence(RefactoringStatus status, IResource element) { if (element == null) { status.addFatalError(RefactoringCoreMessages.ResourceChange_error_no_input); } else if (!element.exists()) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_does_not_exist, BasicElementLabels.getPathLabel(element.getFullPath(), false))); } } @Override public Object getModifiedElement() { return getModifiedResource(); } @Override public String toString() { return getName(); } private long getModificationStamp(IResource resource) { if (!(resource instanceof IFile)) return resource.getModificationStamp(); IFile file= (IFile)resource; ITextFileBuffer buffer= getBuffer(file); if (buffer == null) { return file.getModificationStamp(); } else { IDocument document= buffer.getDocument(); if (document instanceof IDocumentExtension4) { return ((IDocumentExtension4)document).getModificationStamp(); } else { return file.getModificationStamp(); } } } private static ITextFileBuffer getBuffer(IFile file) { ITextFileBufferManager manager= FileBuffers.getTextFileBufferManager(); return manager.getTextFileBuffer(file.getFullPath(), LocationKind.IFILE); } private static class ValidationState { private IResource fResource; private int fKind; private boolean fDirty; private boolean fReadOnly; private long fModificationStamp; private ITextFileBuffer fTextFileBuffer; public static final int RESOURCE= 1; public static final int DOCUMENT= 2; public ValidationState(IResource resource) { fResource= resource; if (resource instanceof IFile) { initializeFile((IFile) resource); } else { initializeResource(resource); } } public void saveIfDirty(RefactoringStatus status, long stampToMatch, IProgressMonitor pm) throws CoreException { if (fDirty) { if (fKind == DOCUMENT && fTextFileBuffer != null && stampToMatch == fModificationStamp) { fTextFileBuffer.commit(pm, false); } else { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_unsaved, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } } public void checkDirty(RefactoringStatus status) { if (fDirty) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_unsaved, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } public void checkReadOnly(RefactoringStatus status) { if (fReadOnly) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_read_only, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } public void checkSameReadOnly(RefactoringStatus status, boolean valueToMatch) { if (fReadOnly != valueToMatch) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_read_only_state_changed, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } public void checkModificationStamp(RefactoringStatus status, long stampToMatch) { if (fKind == DOCUMENT) { if (stampToMatch != IDocumentExtension4.UNKNOWN_MODIFICATION_STAMP && fModificationStamp != stampToMatch) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_has_been_modified, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } else { if (stampToMatch != IResource.NULL_STAMP && fModificationStamp != stampToMatch) { status.addFatalError(Messages.format(RefactoringCoreMessages.ResourceChange_error_has_been_modified, BasicElementLabels.getPathLabel(fResource.getFullPath(), false))); } } } private void initializeFile(IFile file) { fTextFileBuffer= getBuffer(file); if (fTextFileBuffer == null) { initializeResource(file); } else { IDocument document= fTextFileBuffer.getDocument(); fDirty= fTextFileBuffer.isDirty(); fReadOnly= Resources.isReadOnly(file); if (document instanceof IDocumentExtension4) { fKind= DOCUMENT; fModificationStamp= ((IDocumentExtension4) document).getModificationStamp(); } else { fKind= RESOURCE; fModificationStamp= file.getModificationStamp(); } } } private void initializeResource(IResource resource) { fKind= RESOURCE; fDirty= false; fReadOnly= Resources.isReadOnly(resource); fModificationStamp= resource.getModificationStamp(); } } }