Package org.eclipse.core.internal.events

Source Code of org.eclipse.core.internal.events.AutoBuildJob

/*******************************************************************************
* Copyright (c) 2003, 2006 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 - Initial API and implementation
*******************************************************************************/
package org.eclipse.core.internal.events;

import org.eclipse.core.internal.resources.ResourceException;
import org.eclipse.core.internal.resources.Workspace;
import org.eclipse.core.internal.utils.Messages;
import org.eclipse.core.internal.utils.Policy;
import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.Preferences.PropertyChangeEvent;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.osgi.framework.Bundle;

/**
* The job for performing workspace auto-builds, and pre- and post- autobuild
* notification.  This job is run whenever the workspace changes regardless
* of whether autobuild is on or off.
*/
class AutoBuildJob extends Job implements Preferences.IPropertyChangeListener {
  private boolean avoidBuild = false;
  private boolean buildNeeded = false;
  private boolean forceBuild = false;
  /**
   * Indicates that another thread tried to modify the workspace during
   * the autobuild.  The autobuild should be immediately rescheduled
   * so that it will run as soon as the next workspace modification completes.
   */
  private boolean interrupted = false;
  private boolean isAutoBuilding = false;
  private long lastBuild = 0L;
  private Preferences preferences = ResourcesPlugin.getPlugin().getPluginPreferences();
  private final Bundle systemBundle = Platform.getBundle("org.eclipse.osgi"); //$NON-NLS-1$
  private Workspace workspace;

  AutoBuildJob(Workspace workspace) {
    super(Messages.events_building_0);
    setRule(workspace.getRoot());
    setPriority(BUILD);
    isAutoBuilding = workspace.isAutoBuilding();
    this.workspace = workspace;
    this.preferences.addPropertyChangeListener(this);
  }

  /**
   * Used to prevent auto-builds at the end of operations that contain
   * explicit builds
   */
  synchronized void avoidBuild() {
    avoidBuild = true;
  }

  public boolean belongsTo(Object family) {
    return family == ResourcesPlugin.FAMILY_AUTO_BUILD;
  }

  /**
   * Instructs the build job that a build is required.  Ensure the build
   * job is scheduled to run.
   * @param needsBuild Whether a build is required, either due to
   * workspace change or other factor that invalidates the built state.
   */
  synchronized void build(boolean needsBuild) {
    buildNeeded |= needsBuild;
    long delay = computeScheduleDelay();
    int state = getState();
    if (Policy.DEBUG_BUILD_NEEDED)
      Policy.debug("Build requested, needsBuild: " + needsBuild + " state: " + state + " delay: " + delay); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    if (needsBuild && Policy.DEBUG_BUILD_NEEDED_STACK && state != Job.RUNNING)
      new RuntimeException("Build Needed").printStackTrace(); //$NON-NLS-1$
    //don't mess with the interrupt flag if the job is still running
    if (state != Job.RUNNING)
      setInterrupted(false);
    switch (state) {
      case Job.SLEEPING :
        wakeUp(delay);
        break;
      case NONE :
        setSystem(!isAutoBuilding);
        schedule(delay);
        break;
    }
  }

  /**
   * Computes the delay time that autobuild should be scheduled with.  The
   * value will be in the range (MIN_BUILD_DELAY, MAX_BUILD_DELAY).
   */
  private long computeScheduleDelay() {
    return Math.max(Policy.MIN_BUILD_DELAY, Policy.MAX_BUILD_DELAY + lastBuild - System.currentTimeMillis());
  }

  /**
   * The autobuild job has been canceled.  There are two flavours of
   * cancel, explicit user cancelation, and implicit interruption due to another
   * thread trying to modify the workspace.  In the latter case, we must
   * make sure the build is immediately rescheduled if it was interrupted
   * by another thread, so that clients waiting to join autobuild will properly
   * continue waiting
   * @return a status with severity <code>CANCEL</code>
   */
  private synchronized IStatus canceled() {
    //regardless of the form of cancelation, the build state is not happy
    buildNeeded = true;
    //schedule a rebuild immediately if build was implicitly canceled
    if (interrupted) {
      if (Policy.DEBUG_BUILD_INTERRUPT)
        System.out.println("Scheduling rebuild due to interruption"); //$NON-NLS-1$
      setInterrupted(false);
      schedule(computeScheduleDelay());
    }
    return Status.CANCEL_STATUS;
  }

  private void doBuild(IProgressMonitor monitor) throws CoreException, OperationCanceledException {
    monitor = Policy.monitorFor(monitor);
    try {
      monitor.beginTask("", Policy.opWork); //$NON-NLS-1$
      final ISchedulingRule rule = workspace.getRuleFactory().buildRule();
      try {
        workspace.prepareOperation(rule, monitor);
        workspace.beginOperation(true);
        final int trigger = IncrementalProjectBuilder.AUTO_BUILD;
        workspace.broadcastBuildEvent(workspace, IResourceChangeEvent.PRE_BUILD, trigger);
        IStatus result = Status.OK_STATUS;
        try {
          if (shouldBuild())
            result = workspace.getBuildManager().build(trigger, Policy.subMonitorFor(monitor, Policy.opWork));
        } finally {
          //always send POST_BUILD if there has been a PRE_BUILD
          workspace.broadcastBuildEvent(workspace, IResourceChangeEvent.POST_BUILD, trigger);
        }
        if (!result.isOK())
          throw new ResourceException(result);
        buildNeeded = false;
      } finally {
        //building may close the tree, but we are still inside an
        // operation so open it
        if (workspace.getElementTree().isImmutable())
          workspace.newWorkingTree();
        workspace.endOperation(rule, false, Policy.subMonitorFor(monitor, Policy.endOpWork));
      }
    } finally {
      monitor.done();
    }
  }
 
  /**
   * Forces an autobuild to occur, even if nothing has changed since the last
   * build. This is used to force a build after a clean.
   */
  public void forceBuild() {
    forceBuild = true;
  }

  /**
   * Another thread is attempting to modify the workspace. Flag the auto-build
   * as interrupted so that it will cancel and reschedule itself
   */
  synchronized void interrupt() {
    //if already interrupted, do nothing
    if (interrupted)
      return;
    switch (getState()) {
      case NONE :
        return;
      case WAITING :
        //put the job to sleep if it is waiting to run
        setInterrupted(!sleep());
        break;
      case RUNNING :
        //make sure autobuild doesn't interrupt itself
        if (Job.getJobManager().currentJob() == this)
          return;
        setInterrupted(true);
        if (interrupted && Policy.DEBUG_BUILD_INTERRUPT) {
          System.out.println("Autobuild was interrupted:"); //$NON-NLS-1$
          new Exception().fillInStackTrace().printStackTrace();
        }
        break;
    }
    //clear the autobuild avoidance flag if we were interrupted
    if (interrupted)
      avoidBuild = false;
  }

  synchronized boolean isInterrupted() {
    if (interrupted)
      return true;
    //check if another job is blocked by the build job
    if (isBlocking())
      setInterrupted(true);
    return interrupted;
  }

  /* (non-Javadoc)
   * @see org.eclipse.core.runtime.Preferences.IPropertyChangeListener#propertyChange(org.eclipse.core.runtime.Preferences.PropertyChangeEvent)
   */
  public void propertyChange(PropertyChangeEvent event) {
    if (!event.getProperty().equals(ResourcesPlugin.PREF_AUTO_BUILDING))
      return;
    // get the new value of auto-build directly from the preferences
    boolean wasAutoBuilding = isAutoBuilding;
    isAutoBuilding = preferences.getBoolean(ResourcesPlugin.PREF_AUTO_BUILDING);
    //force a build if autobuild has been turned on
    if (!forceBuild && !wasAutoBuilding && isAutoBuilding) {
      forceBuild = true;
      build(false);
    }
  }

  /* (non-Javadoc)
   * @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
   */
  public IStatus run(IProgressMonitor monitor) {
    //synchronized in case build starts during checkCancel
    synchronized (this) {
      if (monitor.isCanceled()) {
        return canceled();
      }
    }
    //if the system is shutting down, don't build
    if (systemBundle.getState() == Bundle.STOPPING)
      return Status.OK_STATUS;
    try {
      doBuild(monitor);
      lastBuild = System.currentTimeMillis();
      //if the build was successful then it should not be recorded as interrupted
      setInterrupted(false);
      return Status.OK_STATUS;
    } catch (OperationCanceledException e) {
      return canceled();
    } catch (CoreException sig) {
      return sig.getStatus();
    }
  }

  /**
   * Sets or clears the interrupted flag.
   */
  private synchronized void setInterrupted(boolean value) {
    interrupted = value;
  }

  /**
   * Returns true if a build is actually needed, and false otherwise.
   */
  private synchronized boolean shouldBuild() {
    try {
      //if auto-build is off then we never run
      if (!workspace.isAutoBuilding())
        return false;
      //build if the workspace requires a build (description changes)
      if (forceBuild)
        return true;
      if (avoidBuild)
        return false;
      //return whether there have been any changes to the workspace tree.
      return buildNeeded;
    } finally {
      //regardless of the result, clear the build flags for next time
      forceBuild = avoidBuild = buildNeeded = false;
    }
  }
}
TOP

Related Classes of org.eclipse.core.internal.events.AutoBuildJob

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.