org.eclipse.ui.actions.WorkspaceModifyOperation.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ui.actions.WorkspaceModifyOperation.java

Source

/*******************************************************************************
 * Copyright (c) 2000, 2008 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.ui.actions;

import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;

import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRunnable;

import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.operation.IThreadListener;

import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;

/**
 * An operation which potentially makes changes to the workspace. All resource
 * modification should be performed using this operation. The primary
 * consequence of using this operation is that events which typically occur as a
 * result of workspace changes (such as the firing of resource deltas,
 * performance of autobuilds, etc.) are generally deferred until the outermost operation
 * has successfully completed.  The platform may still decide to broadcast
 * periodic resource change notifications during the scope of the operation
 * if the operation runs for a long time or another thread modifies the workspace
 * concurrently.
 * <p>
 * If a scheduling rule is provided, the operation will obtain that scheduling
 * rule for the duration of its <code>execute</code> method.  If no scheduling
 * rule is provided, the operation will obtain a scheduling rule that locks
 * the entire workspace for the duration of the operation.
 * </p>
 * <p>
 * Subclasses must implement <code>execute</code> to do the work of the
 * operation.
 * </p>
 * @see ISchedulingRule
 * @see org.eclipse.core.resources.IWorkspace#run(IWorkspaceRunnable, IProgressMonitor)
 *  */
public abstract class WorkspaceModifyOperation implements IRunnableWithProgress, IThreadListener {
    private ISchedulingRule rule;

    /**
     * Creates a new operation.
     */
    protected WorkspaceModifyOperation() {
        this(IDEWorkbenchPlugin.getPluginWorkspace().getRoot());
    }

    /**
     * Creates a new operation that will run using the provided
     * scheduling rule.
     * @param rule  The ISchedulingRule to use or <code>null</code>.
     * @since 3.0
     */
    protected WorkspaceModifyOperation(ISchedulingRule rule) {
        this.rule = rule;
    }

    /**
     * Performs the steps that are to be treated as a single logical workspace
     * change.
     * <p>
     * Subclasses must implement this method.
     * </p>
     *
     * @param monitor the progress monitor to use to display progress and field
     *   user requests to cancel
     * @exception CoreException if the operation fails due to a CoreException
     * @exception InvocationTargetException if the operation fails due to an exception other than CoreException
     * @exception InterruptedException if the operation detects a request to cancel,
     *  using <code>IProgressMonitor.isCanceled()</code>, it should exit by throwing
     *  <code>InterruptedException</code>.  It is also possible to throw
     *  <code>OperationCanceledException</code>, which gets mapped to <code>InterruptedException</code>
     *  by the <code>run</code> method.
     */
    protected abstract void execute(IProgressMonitor monitor)
            throws CoreException, InvocationTargetException, InterruptedException;

    /**
     * The <code>WorkspaceModifyOperation</code> implementation of this
     * <code>IRunnableWithProgress</code> method initiates a batch of changes by
     * invoking the <code>execute</code> method as a workspace runnable
     * (<code>IWorkspaceRunnable</code>).
     */
    public synchronized final void run(IProgressMonitor monitor)
            throws InvocationTargetException, InterruptedException {
        final InvocationTargetException[] iteHolder = new InvocationTargetException[1];
        try {
            IWorkspaceRunnable workspaceRunnable = new IWorkspaceRunnable() {
                public void run(IProgressMonitor pm) throws CoreException {
                    try {
                        execute(pm);
                    } catch (InvocationTargetException e) {
                        // Pass it outside the workspace runnable
                        iteHolder[0] = e;
                    } catch (InterruptedException e) {
                        // Re-throw as OperationCanceledException, which will be
                        // caught and re-thrown as InterruptedException below.
                        throw new OperationCanceledException(e.getMessage());
                    }
                    // CoreException and OperationCanceledException are propagated
                }
            };
            IDEWorkbenchPlugin.getPluginWorkspace().run(workspaceRunnable, rule, IResource.NONE, monitor);
        } catch (CoreException e) {
            throw new InvocationTargetException(e);
        } catch (OperationCanceledException e) {
            throw new InterruptedException(e.getMessage());
        }
        // Re-throw the InvocationTargetException, if any occurred
        if (iteHolder[0] != null) {
            throw iteHolder[0];
        }
    }

    /* (non-Javadoc)
     * @see IThreadListener#threadChange(Thread);
     * @since 3.2
     */
    public void threadChange(Thread thread) {
        //we must make sure we aren't transferring control away from a thread that
        //already owns a scheduling rule because this is deadlock prone (bug 105491)
        if (rule == null) {
            return;
        }
        Job currentJob = Job.getJobManager().currentJob();
        if (currentJob == null) {
            return;
        }
        ISchedulingRule currentRule = currentJob.getRule();
        if (currentRule == null) {
            return;
        }
        throw new IllegalStateException("Cannot fork a thread from a thread owning a rule"); //$NON-NLS-1$
    }

    /**
     * The scheduling rule.  Should not be modified.
     * @return the scheduling rule, or <code>null</code>.
     * @since 3.4
     */
    public ISchedulingRule getRule() {
        return rule;
    }
}