Bug 347599: [refactoring] Provide a way to implement refactorings that
depend on resources that have to be explicitly released
diff --git a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
index 1113f4a..b76e89b 100644
--- a/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
+++ b/org.eclipse.jdt.core.manipulation/META-INF/MANIFEST.MF
@@ -2,14 +2,14 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.jdt.core.manipulation; singleton:=true
-Bundle-Version: 1.4.0.qualifier
+Bundle-Version: 1.5.0.qualifier
 Bundle-Vendor: %providerName
 Bundle-Activator: org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin
 Bundle-Localization: plugin
 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.ltk.core.refactoring;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.jdt.core;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.ltk.core.refactoring;bundle-version="[3.6.0,4.0.0)",
+ org.eclipse.jdt.core;bundle-version="[3.8.0,4.0.0)",
  org.eclipse.core.expressions;bundle-version="[3.4.100,4.0.0)",
  org.eclipse.text;bundle-version="[3.5.0,4.0.0)"
 Bundle-ActivationPolicy: lazy
diff --git a/org.eclipse.jdt.ui.tests/examples/org/eclipse/jdt/ui/examples/TestMoveDescriptorAction.java b/org.eclipse.jdt.ui.tests/examples/org/eclipse/jdt/ui/examples/TestMoveDescriptorAction.java
index 2d8b2c8..1dd1d12 100644
--- a/org.eclipse.jdt.ui.tests/examples/org/eclipse/jdt/ui/examples/TestMoveDescriptorAction.java
+++ b/org.eclipse.jdt.ui.tests/examples/org/eclipse/jdt/ui/examples/TestMoveDescriptorAction.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -31,7 +31,7 @@
 
 import org.eclipse.ltk.core.refactoring.CheckConditionsOperation;
 import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation;
-import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringContribution;
 import org.eclipse.ltk.core.refactoring.RefactoringCore;
 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
@@ -103,14 +103,11 @@
 
 		RefactoringStatus status= new RefactoringStatus();
 
-		Refactoring refactoring= moveDes.createRefactoring(status);
-		PerformRefactoringOperation op= new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS);
-
+		RefactoringContext context= moveDes.createRefactoringContext(status);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(context, CheckConditionsOperation.ALL_CONDITIONS);
 		op.run(monitor);
 	}
 
-
-
 	/* (non-Javadoc)
 	 * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
 	 */
diff --git a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/binary/BinaryRefactoringHistoryWizard.java b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/binary/BinaryRefactoringHistoryWizard.java
index f794e7b..9782f08 100644
--- a/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/binary/BinaryRefactoringHistoryWizard.java
+++ b/org.eclipse.jdt.ui/ui refactoring/org/eclipse/jdt/internal/ui/refactoring/binary/BinaryRefactoringHistoryWizard.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.refactoring.binary;
 
@@ -38,6 +39,7 @@
 
 import org.eclipse.ltk.core.refactoring.Change;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringContribution;
 import org.eclipse.ltk.core.refactoring.RefactoringCore;
 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
@@ -485,7 +487,7 @@
 	 * {@inheritDoc}
 	 */
 	@Override
-	protected Refactoring createRefactoring(RefactoringDescriptor descriptor, RefactoringStatus status, IProgressMonitor monitor) throws CoreException {
+	protected RefactoringContext createRefactoringContext(RefactoringDescriptor descriptor, RefactoringStatus status, IProgressMonitor monitor) throws CoreException {
 		Assert.isNotNull(descriptor);
 
 		createNecessarySourceCode(monitor);
@@ -523,7 +525,7 @@
 				return null;
 			}
 		}
-		return descriptor.createRefactoring(status);
+		return descriptor.createRefactoringContext(status);
 	}
 
 	/**
diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java
index e523656..8e8e3f1 100644
--- a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java
+++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/AllTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -22,6 +22,9 @@
 
 	public static Test suite() {
 		TestSuite suite= new TestSuite("All LTK Refactoring Core Tests"); //$NON-NLS-1$
+		
+		suite.addTestSuite(RefactoringContextTest.class);
+		
 		suite.addTest(ParticipantTests.suite());
 		suite.addTest(RefactoringHistoryTests.suite());
 		suite.addTest(RefactoringScriptingTests.suite());
diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringContextTest.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringContextTest.java
new file mode 100644
index 0000000..d9f6dc6
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/RefactoringContextTest.java
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation 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
+ *
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring.tests;
+
+import junit.framework.TestCase;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CheckConditionsOperation;
+import org.eclipse.ltk.core.refactoring.NullChange;
+import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+
+
+public class RefactoringContextTest extends TestCase {
+
+	private static class TestRefactoring extends Refactoring {
+		RefactoringStatus fInitialConditionStatus= new RefactoringStatus();
+		RefactoringStatus fFinalConditionStatus= new RefactoringStatus();
+
+		public String getName() {
+			return "test Refactoring";
+		}
+
+		public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+			return fInitialConditionStatus;
+		}
+
+		public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+			return fFinalConditionStatus;
+		}
+
+		public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+			return new NullChange();
+		}
+	}
+
+	private static class TestRefactoringContext extends RefactoringContext {
+		int fDisposeCalls;
+
+		public TestRefactoringContext(Refactoring refactoring) {
+			super(refactoring);
+		}
+
+		public void dispose() {
+			super.dispose();
+			fDisposeCalls++;
+		}
+	}
+
+
+	public void testDisposeNormal() throws Exception {
+		TestRefactoring ref= new TestRefactoring();
+		TestRefactoringContext context= new TestRefactoringContext(ref);
+
+		new PerformRefactoringOperation(context, CheckConditionsOperation.ALL_CONDITIONS).run(null);
+		assertEquals(1, context.fDisposeCalls);
+
+		try {
+			context.dispose();
+		} catch (IllegalStateException e) {
+			return; //expected
+		}
+		fail("dispose must not be called twice");
+	}
+
+	public void testDisposeInitialFailed() throws Exception {
+		TestRefactoring ref= new TestRefactoring();
+		ref.fInitialConditionStatus.addFatalError("fail");
+		TestRefactoringContext context= new TestRefactoringContext(ref);
+
+		new PerformRefactoringOperation(context, CheckConditionsOperation.ALL_CONDITIONS).run(null);
+		assertEquals(1, context.fDisposeCalls);
+	}
+
+	public void testDisposeFinalFailed() throws Exception {
+		TestRefactoring ref= new TestRefactoring();
+		ref.fFinalConditionStatus.addFatalError("fail");
+		TestRefactoringContext context= new TestRefactoringContext(ref);
+
+		new PerformRefactoringOperation(context, CheckConditionsOperation.ALL_CONDITIONS).run(null);
+		assertEquals(1, context.fDisposeCalls);
+	}
+
+	public void testDisposeChangeFailed() throws Exception {
+		TestRefactoring ref= new TestRefactoring() {
+			public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+				throw new OperationCanceledException();
+			}
+		};
+		TestRefactoringContext context= new TestRefactoringContext(ref);
+
+		boolean cancelled= false;
+		try {
+			new PerformRefactoringOperation(context, CheckConditionsOperation.ALL_CONDITIONS).run(null);
+		} catch (OperationCanceledException e) {
+			cancelled= true;
+		}
+		assertTrue(cancelled);
+		assertEquals(1, context.fDisposeCalls);
+	}
+}
diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringTests.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringTests.java
index 22993e3..99a042a 100644
--- a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringTests.java
+++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringTests.java
@@ -7,6 +7,7 @@
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
  *******************************************************************************/
 package org.eclipse.ltk.core.refactoring.tests.resource;
 
@@ -35,6 +36,7 @@
 import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
 import org.eclipse.ltk.core.refactoring.PerformRefactoringOperation;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringContribution;
 import org.eclipse.ltk.core.refactoring.RefactoringCore;
 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
@@ -302,14 +304,20 @@
 
 	private Change perform(RefactoringDescriptor descriptor) throws CoreException {
 		RefactoringStatus status= new RefactoringStatus();
-		Refactoring refactoring= descriptor.createRefactoring(status);
-		assertTrue(status.isOK());
+		final RefactoringContext context= descriptor.createRefactoringContext(status);
+		try {
+			final Refactoring refactoring= context != null ? context.getRefactoring() : null;
+			assertTrue(status.isOK());
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS);
-		op.run(null);
-		RefactoringStatus validationStatus= op.getValidationStatus();
-		assertTrue(!validationStatus.hasFatalError() && !validationStatus.hasError());
-		return op.getUndoChange();
+			PerformRefactoringOperation op= new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS);
+			op.run(null);
+			RefactoringStatus validationStatus= op.getValidationStatus();
+			assertTrue(!validationStatus.hasFatalError() && !validationStatus.hasError());
+			return op.getUndoChange();
+		} finally {
+			if (context != null)
+				context.dispose();
+		}
 	}
 
 	private IResource assertMove(IResource source, IContainer destination, String content) throws CoreException, IOException {
diff --git a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringUndoTests.java b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringUndoTests.java
index f048c33..a57ab91 100644
--- a/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringUndoTests.java
+++ b/org.eclipse.ltk.core.refactoring.tests/src/org/eclipse/ltk/core/refactoring/tests/resource/ResourceRefactoringUndoTests.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2008 IBM Corporation and others.
+ * Copyright (c) 2008, 2011 IBM Corporation 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
@@ -135,7 +135,7 @@
 		RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePath(testFile.getFullPath());
 		desc.setNewName(TEST_NEWFILE_NAME);
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FileSnapshot snap= new FileSnapshot(testFile);
 		execute(op);
@@ -160,7 +160,7 @@
 		RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePath(testFolder.getFullPath());
 		desc.setNewName(TEST_NEWFOLDER_NAME);
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FolderSnapshot snap= new FolderSnapshot(testFolder);
 		execute(op);
@@ -184,7 +184,7 @@
 		RenameResourceDescriptor desc= (RenameResourceDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePath(fProject.getProject().getFullPath());
 		desc.setNewName(TEST_NEWPROJECT_NAME);
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		ProjectSnapshot snap= new ProjectSnapshot(fProject.getProject());
 		execute(op);
@@ -206,7 +206,7 @@
 		DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePaths(new IPath[] { testFile.getFullPath() });
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FileSnapshot snap= new FileSnapshot(testFile);
 
@@ -225,7 +225,7 @@
 		DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePaths(new IPath[] { testLinkedFile.getFullPath() });
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FileSnapshot snap= new FileSnapshot(testLinkedFile);
 
@@ -244,7 +244,7 @@
 		DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePaths(new IPath[] { testSubFolder.getFullPath() });
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FolderSnapshot snap= new FolderSnapshot(testSubFolder);
 
@@ -263,7 +263,7 @@
 		DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePaths(new IPath[] { testLinkedFolder.getFullPath() });
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		FolderSnapshot snap= new FolderSnapshot(testLinkedFolder);
 		execute(op);
@@ -280,7 +280,7 @@
 		DeleteResourcesDescriptor desc= (DeleteResourcesDescriptor) renameContribution.createDescriptor();
 		desc.setResourcePaths(new IPath[] { fProject.getProject().getFullPath() });
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 		execute(op);
 		assertFalse("Project delete failed", fProject.getProject().exists());
@@ -312,7 +312,7 @@
 		desc.setResourcePaths(new IPath[] { fProject.getProject().getFullPath() });
 		desc.setDeleteContents(true);
 
-		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoring(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
+		PerformRefactoringOperation op= new PerformRefactoringOperation(desc.createRefactoringContext(new RefactoringStatus()), CheckConditionsOperation.ALL_CONDITIONS);
 
 // we don't snapshot since CONTENT will be deleted
 		execute(op);
diff --git a/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF b/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
index a1ba3e5..bf5fe3f 100644
--- a/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
+++ b/org.eclipse.ltk.core.refactoring/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ltk.core.refactoring; singleton:=true
-Bundle-Version: 3.5.300.qualifier
+Bundle-Version: 3.6.0.qualifier
 Bundle-Activator: org.eclipse.ltk.internal.core.refactoring.RefactoringCorePlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringHistoryOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringHistoryOperation.java
index 6adaf4b..ed9d9ec 100644
--- a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringHistoryOperation.java
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringHistoryOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 IBM Corporation 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
  *******************************************************************************/
 package org.eclipse.ltk.core.refactoring;
 
@@ -127,6 +128,7 @@
 	 *             if an error occurs while creating the refactoring instance
 	 *
 	 * @since 3.4
+	 * @deprecated since 3.6. Override {@link #createRefactoringContext(RefactoringDescriptor, RefactoringStatus, IProgressMonitor)} instead
 	 */
 	protected Refactoring createRefactoring(final RefactoringDescriptor descriptor, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
 		try {
@@ -140,6 +142,43 @@
 	}
 
 	/**
+	 * Method which is called to create a refactoring context from a refactoring descriptor.
+	 * The refactoring context must contain a refactoring in an initialized state at the return
+	 * of the method call.
+	 * <p>
+	 * A caller of this method must ensure that {@link RefactoringContext#dispose()} is eventually called.
+	 * </p>
+	 * 
+	 * <p>
+	 * The default implementation delegates the task to the refactoring descriptor.
+	 * </p>
+	 *
+	 * @param descriptor
+	 *            the refactoring descriptor
+	 * @param status
+	 *            a refactoring status to describe the outcome of the initialization
+	 * @param monitor
+	 *            the progress monitor to use
+	 * @return the refactoring context, or <code>null</code> if this refactoring descriptor
+	 *            represents the unknown refactoring, or if no refactoring contribution is
+	 *            available for this refactoring descriptor
+	 * @throws CoreException
+	 *             if an error occurs while creating the refactoring context
+	 * @since 3.6
+	 */
+	protected RefactoringContext createRefactoringContext(final RefactoringDescriptor descriptor,
+			final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
+		try {
+			Assert.isNotNull(descriptor);
+			return descriptor.createRefactoringContext(status);
+		} finally {
+			if (monitor != null) {
+				monitor.done();
+			}
+		}
+	}
+
+	/**
 	 * Returns the execution status. Guaranteed not to be <code>null</code>.
 	 *
 	 * @return the status of the session
@@ -177,15 +216,16 @@
 			for (int index= 0; index < proxies.length; index++) {
 				final RefactoringDescriptor descriptor= proxies[index].requestDescriptor(new SubProgressMonitor(monitor, 10, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
 				if (descriptor != null) {
-					Refactoring refactoring= null;
+					RefactoringContext context= null;
 					RefactoringStatus status= new RefactoringStatus();
 					try {
 						try {
-							refactoring= createRefactoring(descriptor, status, new SubProgressMonitor(monitor, 30, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
+							context= createRefactoringContext(descriptor, status, new SubProgressMonitor(monitor, 30, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
 						} catch (CoreException exception) {
 							status.merge(RefactoringStatus.create(exception.getStatus()));
 						}
-						if (refactoring != null && !status.hasFatalError()) {
+						if (context != null && !status.hasFatalError()) {
+							Refactoring refactoring= context.getRefactoring();
 							final PerformRefactoringOperation operation= new PerformRefactoringOperation(refactoring, CheckConditionsOperation.ALL_CONDITIONS);
 							try {
 								status.merge(aboutToPerformRefactoring(refactoring, descriptor, new SubProgressMonitor(monitor, 30, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)));
@@ -201,6 +241,8 @@
 						}
 					} finally {
 						fExecutionStatus.merge(status);
+						if (context != null)
+							context.dispose();
 					}
 				}
 			}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java
index 04bb218..2ce139d 100644
--- a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/PerformRefactoringOperation.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2008 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -39,6 +39,7 @@
 public class PerformRefactoringOperation implements IWorkspaceRunnable {
 
 	private int fStyle;
+	private RefactoringContext fRefactoringContext;
 	private Refactoring fRefactoring;
 
 	private RefactoringStatus fPreconditionStatus;
@@ -53,6 +54,7 @@
 	 * @param refactoring the refactoring to perform
 	 * @param style the condition checking style as defined by
 	 *  {@link CheckConditionsOperation}
+	 * @see #PerformRefactoringOperation(RefactoringContext, int) 
 	 */
 	public PerformRefactoringOperation(Refactoring refactoring, int style) {
 		Assert.isNotNull(refactoring);
@@ -61,6 +63,27 @@
 	}
 
 	/**
+	 * Create a new perform refactoring operation. The operation will not
+	 * perform the refactoring if the refactoring's condition checking returns
+	 * an error	of severity {@link RefactoringStatus#FATAL}.
+	 * <p>
+	 * The caller must ensure that the operation is run exactly once. The implementation
+	 * of {@link #run(IProgressMonitor)} will call {@link RefactoringContext#dispose()}.
+	 * </p>
+	 *
+	 * @param refactoringContext the refactoring context to perform
+	 * @param style the condition checking style as defined by
+	 *  {@link CheckConditionsOperation}
+	 * @since 3.6
+	 */
+	public PerformRefactoringOperation(RefactoringContext refactoringContext, int style) {
+		Assert.isNotNull(refactoringContext);
+		fRefactoringContext= refactoringContext;
+		fRefactoring= fRefactoringContext.getRefactoring();
+		fStyle= style;
+	}
+	
+	/**
 	 * Return the refactoring status of the condition checking.
 	 *
 	 * @return the refactoring status of the condition checking or <code>null</code>
@@ -95,23 +118,28 @@
 	 * {@inheritDoc}
 	 */
 	public void run(IProgressMonitor monitor) throws CoreException {
-		if (monitor == null)
-			monitor= new NullProgressMonitor();
-		monitor.beginTask("", 10); //$NON-NLS-1$
-		final CreateChangeOperation create= new CreateChangeOperation(new CheckConditionsOperation(fRefactoring, fStyle), RefactoringStatus.FATAL);
-		create.run(new SubProgressMonitor(monitor, 6));
-		fPreconditionStatus= create.getConditionCheckingStatus();
-		if (fPreconditionStatus.hasFatalError()) {
-			monitor.done();
-			return;
-		}
-		final Change change= create.getChange();
-		if (change != null) {
-			final PerformChangeOperation perform= new PerformChangeOperation(change);
-			perform.setUndoManager(RefactoringCore.getUndoManager(), fRefactoring.getName());
-			perform.run(new SubProgressMonitor(monitor, 2));
-			fValidationStatus= perform.getValidationStatus();
-			fUndo= perform.getUndoChange();
+		try {
+			if (monitor == null)
+				monitor= new NullProgressMonitor();
+			monitor.beginTask("", 10); //$NON-NLS-1$
+			final CreateChangeOperation create= new CreateChangeOperation(new CheckConditionsOperation(fRefactoring, fStyle), RefactoringStatus.FATAL);
+			create.run(new SubProgressMonitor(monitor, 6));
+			fPreconditionStatus= create.getConditionCheckingStatus();
+			if (fPreconditionStatus.hasFatalError()) {
+				monitor.done();
+				return;
+			}
+			final Change change= create.getChange();
+			if (change != null) {
+				final PerformChangeOperation perform= new PerformChangeOperation(change);
+				perform.setUndoManager(RefactoringCore.getUndoManager(), fRefactoring.getName());
+				perform.run(new SubProgressMonitor(monitor, 2));
+				fValidationStatus= perform.getValidationStatus();
+				fUndo= perform.getUndoChange();
+			}
+		} finally {
+			if (fRefactoringContext != null)
+				fRefactoringContext.dispose();
 		}
 	}
 }
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java
index 2263ac8..fde9a6d 100644
--- a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/Refactoring.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2009 IBM Corporation and others.
+ * Copyright (c) 2000, 2011 IBM Corporation 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
@@ -60,6 +60,8 @@
  * <p>
  * The class should be subclassed by clients wishing to implement new refactorings.
  * </p>
+ * 
+ * @see RefactoringContext
  *
  * @since 3.0
  */
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringContext.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringContext.java
new file mode 100644
index 0000000..5b5cc12
--- /dev/null
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringContext.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011 Google, Inc 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
+ *
+ * Contributors:
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
+ *     IBM Corporation - bug fixes
+ *******************************************************************************/
+package org.eclipse.ltk.core.refactoring;
+
+/**
+ * <p>
+ * Refactoring context is a disposable object that can be used by a refactoring to hold resources
+ * that have to be explicitly released. The refactoring context is guaranteed to receive
+ * a {@link #dispose()} call after the associated refactoring has finished or produced an error.
+ * At this point, the refactoring context must release all resources and detach all listeners.
+ * A refactoring context can only be disposed once; it cannot be reused.
+ * </p>
+ * <p>
+ * This class is intended to be subclassed by clients wishing to implement new refactorings that
+ * depend on resources that have to be explicitly released.
+ * </p>
+ * @since 3.6
+ */
+public class RefactoringContext {
+	private Refactoring fRefactoring;
+
+	/**
+	 * Creates a context for the given refactoring.
+	 * 
+	 * @param refactoring The refactoring associated with the context. Cannot be <code>null</code>.
+	 * @throws NullPointerException if refactoring is <code>null</code>.
+	 */
+	public RefactoringContext(Refactoring refactoring) {
+		if (refactoring == null)
+			throw new NullPointerException();
+		fRefactoring= refactoring;
+	}
+
+	/**
+	 * Returns the refactoring associated with the context.
+	 * <p>
+	 * The returned refactoring must be in an initialized state, i.e. ready to
+	 * be executed via {@link PerformRefactoringOperation}.
+	 * </p>
+	 * @return The refactoring associated with the context.
+	 * @nooverride This method is not intended to be re-implemented or extended by clients.
+	 */
+	public Refactoring getRefactoring() {
+		return fRefactoring;
+	}
+
+	/**
+	 * Disposes of the context. This method will be called exactly once during the life cycle
+	 * of the context after the associated refactoring has finished or produced an error.
+	 * <p>
+	 * Subclasses may extend this method (must call super).
+	 * </p>
+	 */
+	public void dispose() {
+		if (fRefactoring == null)
+			throw new IllegalStateException("dispose() called more than once."); //$NON-NLS-1$
+		fRefactoring= null;
+	}
+}
diff --git a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringDescriptor.java b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringDescriptor.java
index 0491a1b..9f3ccbc 100644
--- a/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringDescriptor.java
+++ b/org.eclipse.ltk.core.refactoring/src/org/eclipse/ltk/core/refactoring/RefactoringDescriptor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 IBM Corporation 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
  *******************************************************************************/
 package org.eclipse.ltk.core.refactoring;
 
@@ -229,28 +230,57 @@
 	/**
 	 * Creates the a new refactoring instance for this refactoring descriptor.
 	 * <p>
-	 * This method is used by the refactoring framework to instantiate a
-	 * refactoring from a refactoring descriptor, in order to apply it later on
-	 * a local or remote workspace.
-	 * </p>
-	 * <p>
 	 * The returned refactoring must be in an initialized state, i.e. ready to
 	 * be executed via {@link PerformRefactoringOperation}.
 	 * </p>
+	 * <p>
+	 * This method is not intended to be called directly from code that does not belong to this
+	 * class and its subclasses. External code should call
+	 * {@link #createRefactoringContext(RefactoringStatus)} and obtain the refactoring object from
+	 * the refactoring context.
+	 * </p>
 	 *
 	 * @param status
-	 *            a refactoring status used to describe the outcome of the
-	 *            initialization
+	 *          a refactoring status used to describe the outcome of the initialization
 	 * @return the refactoring, or <code>null</code> if this refactoring
 	 *         descriptor represents the unknown refactoring, or if no
 	 *         refactoring contribution is available for this refactoring
 	 *         descriptor which is capable to create a refactoring
 	 * @throws CoreException
-	 *             if an error occurs while creating the refactoring instance
+	 *         if an error occurs while creating the refactoring instance
 	 */
 	public abstract Refactoring createRefactoring(RefactoringStatus status) throws CoreException;
 
 	/**
+	 * Creates the a new refactoring context and the associated refactoring instance for this
+	 * refactoring descriptor.
+	 * <p>
+	 * This method is used by the refactoring framework to instantiate a refactoring
+	 * from a refactoring descriptor, in order to apply it later on a local or remote workspace.
+	 * </p>
+	 * <p>
+	 * The default implementation of this method wraps the refactoring in a trivial refactoring
+	 * context. Subclasses may override this method to create a custom refactoring context.
+	 * </p>
+	 *
+	 * @param status
+	 * 			a refactoring status used to describe the outcome of the initialization
+	 * @return the refactoring context, or <code>null</code> if this refactoring
+	 *         	descriptor represents the unknown refactoring, or if no
+	 *         	refactoring contribution is available for this refactoring
+	 *         	descriptor which is capable to create a refactoring.
+	 * @throws CoreException
+	 *          if an error occurs while creating the refactoring context
+	 * @since 3.6
+	 */
+	public RefactoringContext createRefactoringContext(RefactoringStatus status) throws CoreException {
+		Refactoring refactoring= createRefactoring(status);
+		if (refactoring == null)
+			return null;
+		return new RefactoringContext(refactoring);
+	}
+	
+	/**
 	 * {@inheritDoc}
 	 */
 	public final boolean equals(final Object object) {
diff --git a/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF b/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
index 6534a86..319d25f 100644
--- a/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
+++ b/org.eclipse.ltk.ui.refactoring/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.ltk.ui.refactoring; singleton:=true
-Bundle-Version: 3.6.0.qualifier
+Bundle-Version: 3.7.0.qualifier
 Bundle-Activator: org.eclipse.ltk.internal.ui.refactoring.RefactoringUIPlugin
 Bundle-ActivationPolicy: lazy
 Bundle-Vendor: %providerName
@@ -23,7 +23,7 @@
  org.eclipse.core.filebuffers;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.filesystem;bundle-version="[1.2.0,2.0.0)",
  org.eclipse.core.resources;bundle-version="[3.5.0,4.0.0)",
- org.eclipse.ltk.core.refactoring;bundle-version="[3.5.0,4.0.0)",
+ org.eclipse.ltk.core.refactoring;bundle-version="[3.6.0,4.0.0)",
  org.eclipse.jface.text;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.ui;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.ui.navigator;bundle-version="[3.3.200,4.0.0)",
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizard.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizard.java
index 5240388..99e122f 100644
--- a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizard.java
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizard.java
@@ -33,6 +33,7 @@
 import org.eclipse.ltk.core.refactoring.CreateChangeOperation;
 import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringCore;
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 import org.eclipse.ltk.internal.ui.refactoring.ChangeExceptionHandler;
@@ -154,6 +155,7 @@
 	private static final int LAST= 1 << 8;
 
 	private final int fFlags;
+	private final RefactoringContext fRefactoringContext;
 	private final Refactoring fRefactoring;
 	private String fDefaultPageTitle;
 
@@ -180,11 +182,31 @@
 	 *  taken as a default.
 	 */
 	public RefactoringWizard(Refactoring refactoring, int flags) {
+		this(null, refactoring, flags);
 		Assert.isNotNull(refactoring);
+	}
+	
+	/**
+	 * Creates a new refactoring wizard for the given refactoring context.
+	 *
+	 * @param refactoringContext the refactoringContext the wizard is presenting
+	 * @param flags flags specifying the behavior of the wizard. If neither
+	 *  <code>WIZARD_BASED_USER_INTERFACE</code> nor <code>DIALOG_BASED_UESR_INTERFACE</code>
+	 *  is specified then <code>WIZARD_BASED_USER_INTERFACE</code> will be
+	 *  taken as a default.
+	 * @since 3.7
+	 */
+	public RefactoringWizard(RefactoringContext refactoringContext, int flags) {
+		this(refactoringContext, null, flags);
+		Assert.isNotNull(refactoringContext);
+	}
+	
+	private RefactoringWizard(RefactoringContext refactoringContext, Refactoring refactoring, int flags) {
 		Assert.isTrue(flags < LAST);
 		if ((flags & DIALOG_BASED_USER_INTERFACE) == 0)
 			flags |= WIZARD_BASED_USER_INTERFACE;
 		Assert.isTrue((flags & DIALOG_BASED_USER_INTERFACE) != 0 || (flags & WIZARD_BASED_USER_INTERFACE) != 0);
+		fRefactoringContext= refactoringContext;
 		fRefactoring= refactoring;
 		fFlags= flags;
 		setNeedsProgressMonitor(true);
@@ -200,11 +222,21 @@
 	 *
 	 * @return the wizard's refactoring
 	 */
-	public final Refactoring getRefactoring(){
+	public final Refactoring getRefactoring() {
 		return fRefactoring;
 	}
 
 	/**
+	 * Returns the refactoring context this wizard is associated with, or <code>null</code> if none.
+	 *
+	 * @return the wizard's refactoring context or <code>null</code>
+	 * @since 3.7
+	 */
+	public final RefactoringContext getRefactoringContext() {
+		return fRefactoringContext;
+	}
+	
+	/**
 	 * Returns the refactoring wizard flags that have been set for this wizard.
 	 * Note that the set of valid flags may grow in the future.
 	 *
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizardOpenOperation.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizardOpenOperation.java
index 3044fc8..c3a3836 100644
--- a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizardOpenOperation.java
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/RefactoringWizardOpenOperation.java
@@ -34,6 +34,7 @@
 
 import org.eclipse.ltk.core.refactoring.CheckConditionsOperation;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
 import org.eclipse.ltk.internal.ui.refactoring.ExceptionHandler;
 import org.eclipse.ltk.internal.ui.refactoring.RefactoringUIMessages;
@@ -67,6 +68,11 @@
 
 	/**
 	 * Creates a new refactoring wizard starter for the given wizard.
+	 * <p>
+	 * If the wizard was created via {@link RefactoringWizard#RefactoringWizard(RefactoringContext, int)},
+	 * then this operation will also {@link RefactoringContext#dispose() dispose} of the context
+	 * at the end of all <code>run</code> methods.
+	 * </p>
 	 *
 	 * @param wizard the wizard to open a dialog for
 	 */
@@ -187,6 +193,9 @@
 				} finally {
 					manager.endRule(ResourcesPlugin.getWorkspace().getRoot());
 					refactoring.setValidationContext(null);
+					RefactoringContext refactoringContext= fWizard.getRefactoringContext();
+					if (refactoringContext != null)
+						refactoringContext.dispose();
 				}
 			}
 		};
diff --git a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/history/RefactoringHistoryWizard.java b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/history/RefactoringHistoryWizard.java
index c00fe40..26cc07f 100644
--- a/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/history/RefactoringHistoryWizard.java
+++ b/org.eclipse.ltk.ui.refactoring/src/org/eclipse/ltk/ui/refactoring/history/RefactoringHistoryWizard.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * Copyright (c) 2005, 2011 IBM Corporation 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
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
  *******************************************************************************/
 package org.eclipse.ltk.ui.refactoring.history;
 
@@ -57,6 +58,7 @@
 import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
 import org.eclipse.ltk.core.refactoring.PerformRefactoringHistoryOperation;
 import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringContext;
 import org.eclipse.ltk.core.refactoring.RefactoringCore;
 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
 import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
@@ -553,6 +555,7 @@
 	 *         descriptor
 	 * @throws CoreException
 	 *             if an error occurs while creating the refactoring instance
+	 * @deprecated since 3.6. Override {@link #createRefactoringContext(RefactoringDescriptor, RefactoringStatus, IProgressMonitor)} instead
 	 */
 	protected Refactoring createRefactoring(final RefactoringDescriptor descriptor, final RefactoringStatus status) throws CoreException {
 		Assert.isNotNull(descriptor);
@@ -581,6 +584,7 @@
 	 *             if an error occurs while creating the refactoring instance
 	 *
 	 * @since 3.4
+	 * @deprecated since 3.7. Override {@link #createRefactoringContext(RefactoringDescriptor, RefactoringStatus, IProgressMonitor)} instead
 	 */
 	protected Refactoring createRefactoring(final RefactoringDescriptor descriptor, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
 		final Refactoring refactoring= createRefactoring(descriptor, status);
@@ -594,6 +598,43 @@
 	}
 
 	/**
+	 * Creates a refactoring context from the specified refactoring descriptor.
+	 * <p>
+	 * The default implementation calls
+	 * {@link RefactoringDescriptor#createRefactoringContext(RefactoringStatus)} followed by
+	 * {@link #aboutToPerformRefactoring(Refactoring, RefactoringDescriptor, IProgressMonitor)}.
+	 * Implementors can replace this implementation.
+	 * </p>
+	 *
+	 * @param descriptor
+	 *            the refactoring descriptor
+	 * @param status
+	 *            the refactoring status
+	 * @param monitor
+	 *            the progress monitor to use
+	 * @return the refactoring context, or <code>null</code> if this refactoring descriptor
+	 *         represents the unknown refactoring, or if no refactoring contribution is available
+	 *         for this refactoring descriptor
+	 * @throws CoreException
+	 *             if an error occurs while creating the refactoring context
+	 *
+	 * @since 3.7
+	 */
+	protected RefactoringContext createRefactoringContext(final RefactoringDescriptor descriptor, final RefactoringStatus status, final IProgressMonitor monitor) throws CoreException {
+		Assert.isNotNull(descriptor);
+		final RefactoringContext context= descriptor.createRefactoringContext(status);
+		if (context != null) {
+			final Refactoring refactoring= context.getRefactoring();
+			status.merge(aboutToPerformRefactoring(refactoring, descriptor, monitor));
+			if (!status.hasFatalError())
+				return context;
+		} else {
+			status.addFatalError(Messages.format(RefactoringUIMessages.RefactoringHistoryWizard_error_instantiate_refactoring, descriptor.getDescription()));
+		}
+		return null;
+	}
+
+	/**
 	 * {@inheritDoc}
 	 */
 	public void dispose() {
@@ -825,33 +866,39 @@
 							service.connect();
 							final RefactoringDescriptor descriptor= proxy.requestDescriptor(new SubProgressMonitor(monitor, 10, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
 							if (descriptor != null) {
-								final Refactoring refactoring= createRefactoring(descriptor, status, new SubProgressMonitor(monitor, 60, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
-								if (refactoring != null && status.isOK()) {
-									fPreviewPage.setRefactoring(refactoring);
-									fErrorPage.setRefactoring(refactoring);
-									status.merge(checkConditions(refactoring, new SubProgressMonitor(monitor, 20, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL), CheckConditionsOperation.INITIAL_CONDITONS));
-									if (!status.isOK()) {
-										prepareErrorPage(status, proxy, status.hasFatalError(), last);
-										result[0]= fErrorPage;
-									} else {
-										status.merge(checkConditions(refactoring, new SubProgressMonitor(monitor, 65, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL), CheckConditionsOperation.FINAL_CONDITIONS));
+								final RefactoringContext context= createRefactoringContext(descriptor, status, new SubProgressMonitor(monitor, 60, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
+								try {
+									if (context != null && status.isOK()) {
+										final Refactoring refactoring= context.getRefactoring();
+										fPreviewPage.setRefactoring(refactoring);
+										fErrorPage.setRefactoring(refactoring);
+										status.merge(checkConditions(refactoring, new SubProgressMonitor(monitor, 20, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL), CheckConditionsOperation.INITIAL_CONDITONS));
 										if (!status.isOK()) {
 											prepareErrorPage(status, proxy, status.hasFatalError(), last);
 											result[0]= fErrorPage;
 										} else {
-											final Change change= createChange(refactoring, new SubProgressMonitor(monitor, 5, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
-											getShell().getDisplay().syncExec(new Runnable() {
-
-												public final void run() {
-													fPreviewPage.setChange(change);
-												}
-											});
-											result[0]= fPreviewPage;
+											status.merge(checkConditions(refactoring, new SubProgressMonitor(monitor, 65, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL), CheckConditionsOperation.FINAL_CONDITIONS));
+											if (!status.isOK()) {
+												prepareErrorPage(status, proxy, status.hasFatalError(), last);
+												result[0]= fErrorPage;
+											} else {
+												final Change change= createChange(refactoring, new SubProgressMonitor(monitor, 5, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
+												getShell().getDisplay().syncExec(new Runnable() {
+	
+													public final void run() {
+														fPreviewPage.setChange(change);
+													}
+												});
+												result[0]= fPreviewPage;
+											}
 										}
+									} else {
+										prepareErrorPage(status, proxy, status.hasFatalError(), last);
+										result[0]= fErrorPage;
 									}
-								} else {
-									prepareErrorPage(status, proxy, status.hasFatalError(), last);
-									result[0]= fErrorPage;
+								} finally {
+									if (context != null)
+										context.dispose();
 								}
 							} else {
 								status.merge(RefactoringStatus.createFatalErrorStatus(RefactoringUIMessages.RefactoringHistoryWizard_error_resolving_refactoring));
@@ -1031,8 +1078,8 @@
 			}
 			final PerformRefactoringHistoryOperation operation= new PerformRefactoringHistoryOperation(new RefactoringHistoryImplementation(descriptors)) {
 
-				protected Refactoring createRefactoring(final RefactoringDescriptor descriptor, final RefactoringStatus state, IProgressMonitor monitor) throws CoreException {
-					return RefactoringHistoryWizard.this.createRefactoring(descriptor, state, monitor);
+				protected RefactoringContext createRefactoringContext(final RefactoringDescriptor descriptor, final RefactoringStatus state, IProgressMonitor monitor) throws CoreException {
+					return RefactoringHistoryWizard.this.createRefactoringContext(descriptor, state, monitor);
 				}
 
 				protected void refactoringPerformed(final Refactoring refactoring, final IProgressMonitor monitor) {