Package org.springframework.ide.eclipse.core.internal.project

Source Code of org.springframework.ide.eclipse.core.internal.project.SpringProjectContributionManager$ResourceTreeVisitor

/*******************************************************************************
* Copyright (c) 2007, 2013 Spring IDE Developers
* 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:
*     Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.core.internal.project;

import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.ISafeRunnable;
import org.eclipse.core.runtime.SafeRunner;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.springframework.ide.eclipse.core.SpringCoreUtils;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidatorDefinition;
import org.springframework.ide.eclipse.core.internal.model.validation.ValidatorDefinitionFactory;
import org.springframework.ide.eclipse.core.model.validation.IValidator;
import org.springframework.ide.eclipse.core.project.DefaultProjectContributorState;
import org.springframework.ide.eclipse.core.project.IProjectBuilder;
import org.springframework.ide.eclipse.core.project.IProjectContributionEventListener;
import org.springframework.ide.eclipse.core.project.IProjectContributor;
import org.springframework.ide.eclipse.core.project.IProjectContributorState;
import org.springframework.ide.eclipse.core.project.IProjectContributorStateAware;
import org.springframework.ide.eclipse.core.project.ProjectBuilderDefinition;
import org.springframework.ide.eclipse.core.project.ProjectBuilderDefinitionFactory;
import org.springframework.ide.eclipse.core.project.ProjectContributionEventListenerFactory;

/**
* Incremental project builder which implements the Strategy GOF pattern. For every modified {@link IResource} within a
* Spring project all implementations of the interface {@link IProjectBuilder} provided via the extension point
* <code>org.springframework.ide.eclipse.core.builders</code> and the interface {@link IValidator} provided via the
* extension point <code>org.springframework.ide.eclipse.core.validators</code> are called.
* <p>
* This {@link IncrementalProjectBuilder} makes state in form of an instance of {@link IProjectContributorState} for the
* {@link IProjectContributor} accessible. This state should be used to store arbitrary state object in order to save
* calculation time for subsequent {@link IValidator} or {@link IProjectBuilder}.
* <p>
* {@link IProjectBuilder} or {@link IValidator} implementations that want to access the state should implement the
* {@link IProjectContributorStateAware} interface to a call back with the current state.
*
* @author Torsten Juergeleit
* @author Christian Dupuis
* @author Martin Lippert
*
* @since 2.0
* @see IProjectContributor
* @see IProjectBuilder
* @see IValidator
* @see IProjectContributorState
*/
public class SpringProjectContributionManager extends IncrementalProjectBuilder {
 
  private static Object dummyMapObject = new Object();
  private static Map<String, Object> classpathChanged = new ConcurrentHashMap<String, Object>();
 
  /**
   * indicate that the classpath changed for the given project since the last build
   * This mirrors the same behavior as the JavaBuilder, which keeps a state between
   * builds and checks for classpath changes at every build.
   *
   * This is triggered by a element change listener in SpringModel that keeps listening
   * for classpath changes.
   *
   * @param projectName The name of the project
   */
  public static void classpathChanged(String projectName) {
    classpathChanged.put(projectName, dummyMapObject);
  }

  /**
   * {@inheritDoc}
   */
  protected final IProject[] build(final int kind, Map args, final IProgressMonitor monitor) throws CoreException {
    final IProject project = getProject();
    final IResourceDelta delta = getDelta(project);

    final List<ProjectBuilderDefinition> builderDefinitions = ProjectBuilderDefinitionFactory
        .getProjectBuilderDefinitions();
    final List<ValidatorDefinition> validatorDefinitions = ValidatorDefinitionFactory.getValidatorDefinitions();
    final List<IProjectContributionEventListener> listeners = ProjectContributionEventListenerFactory
        .getProjectContributionEventListeners();

    // Set up the state object
    final IProjectContributorState state = prepareState(project, builderDefinitions, validatorDefinitions);
   
    // check for classpath changes (that require a full build)
    Object removed = classpathChanged.remove(project.getName());
    final int buildKind = removed != null ? IncrementalProjectBuilder.FULL_BUILD : kind;
   
    // Fire start event on listeners
    for (final IProjectContributionEventListener listener : listeners) {
      execute(new SafeExecutableWithMonitor() {
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.start(buildKind, delta, builderDefinitions, validatorDefinitions, state, project, subMonitor);
        }
      }, monitor);

    }

    // At first run all builders
    for (ProjectBuilderDefinition builderDefinition : builderDefinitions) {
      if (builderDefinition.isEnabled(project)) {
        Set<IResource> affectedResources = getAffectedResources(builderDefinition.getProjectBuilder(), project,
            buildKind, delta);
        runBuilder(builderDefinition, affectedResources, buildKind, monitor, listeners);
      }
    }

    // Finally run all validators
    for (ValidatorDefinition validatorDefinition : validatorDefinitions) {
      if (validatorDefinition.isEnabled(project)) {
        Set<IResource> affectedResources = getAffectedResources(validatorDefinition.getValidator(), project, buildKind, delta);
        runValidator(validatorDefinition, affectedResources, buildKind, monitor, listeners);
      }
    }

    // Fire end event on listeners
    for (final IProjectContributionEventListener listener : listeners) {
      execute(new SafeExecutableWithMonitor() {
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.finish(buildKind, delta, builderDefinitions, validatorDefinitions, state, project, subMonitor);
        }
      }, monitor);
    }

    return null;
  }

  /**
   * Collects all affected resources from the given {@link IResourceDelta} and {@link IProjectContributor}.
   */
  private Set<IResource> getAffectedResources(IProjectContributor contributor, IProject project, int kind,
      IResourceDelta delta) throws CoreException {
    Set<IResource> affectedResources;
    if (delta == null || kind == IncrementalProjectBuilder.FULL_BUILD) {
      ResourceTreeVisitor visitor = new ResourceTreeVisitor(contributor);
      project.accept(visitor);
      affectedResources = visitor.getResources();
    }
    else {
      ResourceDeltaVisitor visitor = new ResourceDeltaVisitor(contributor, kind);
      delta.accept(visitor);
      affectedResources = visitor.getResources();
    }
    return affectedResources;
  }

  /**
   * Instantiate the {@link IProjectContributorState} object. The state object is then passed to any
   * {@link IProjectBuilder} and {@link IValidator} that implements the {@link IProjectContributorStateAware}
   * interface.
   * <p>
   * This implementation creates an instance of {@link DefaultProjectContributorState}.
   */
  private IProjectContributorState prepareState(IProject project, List<ProjectBuilderDefinition> builderDefinitions,
      List<ValidatorDefinition> validatorDefinitions) {

    IProjectContributorState context = new DefaultProjectContributorState();
    context.hold(project);
   
    for (ProjectBuilderDefinition builderDefinition : builderDefinitions) {
      if (builderDefinition.isEnabled(project)
          && builderDefinition.getProjectBuilder() instanceof IProjectContributorStateAware) {
        ((IProjectContributorStateAware) builderDefinition.getProjectBuilder())
            .setProjectContributorState(context);
      }
    }

    for (ValidatorDefinition validatorDefinition : validatorDefinitions) {
      if (validatorDefinition.isEnabled(project)
          && validatorDefinition.getValidator() instanceof IProjectContributorStateAware) {
        ((IProjectContributorStateAware) validatorDefinition.getValidator())
            .setProjectContributorState(context);
      }
    }

    return context;
  }

  /**
   * Runs all given {@link IProjectBuilder} in the order as they are given in the set.
   */
  private void runBuilder(final ProjectBuilderDefinition builderDefinition, final Set<IResource> affectedResources,
      final int kind, IProgressMonitor monitor, final List<IProjectContributionEventListener> listeners) {
   
    for (final IProjectContributionEventListener listener : listeners) {

      execute(new SafeExecutableWithMonitor() {

        @SuppressWarnings("deprecation")
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.startContributor(builderDefinition.getProjectBuilder(), affectedResources, subMonitor);
          listener.startProjectBuilder(builderDefinition, affectedResources, subMonitor);
        }
      }, monitor);

    }

    execute(new SafeExecutableWithMonitor() {

      public void execute(IProgressMonitor subMonitor) throws Exception {
        builderDefinition.getProjectBuilder().build(affectedResources, kind, subMonitor);
      }
    }, monitor);

    for (final IProjectContributionEventListener listener : listeners) {
     
      execute(new SafeExecutableWithMonitor() {
       
        @SuppressWarnings("deprecation")
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.finishContributor(builderDefinition.getProjectBuilder(), affectedResources, subMonitor);
          listener.finishProjectBuilder(builderDefinition, affectedResources, subMonitor);
        }
      }, monitor);
     
    }
  }

  /**
   * Runs all given {@link IValidator} in the order as they are given in the set.
   */
  private void runValidator(final ValidatorDefinition validatorDefinition, final Set<IResource> affectedResources,
      final int kind, IProgressMonitor monitor, List<IProjectContributionEventListener> listeners) {

    for (final IProjectContributionEventListener listener : listeners) {

      execute(new SafeExecutableWithMonitor() {

        @SuppressWarnings("deprecation")
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.startContributor(validatorDefinition.getValidator(), affectedResources, subMonitor);
          listener.startValidator(validatorDefinition, affectedResources, subMonitor);
        }
      }, monitor);

    }

    execute(new SafeExecutableWithMonitor() {

      public void execute(IProgressMonitor subMonitor) throws Exception {
        validatorDefinition.getValidator().validate(affectedResources, kind, subMonitor);
      }
    }, monitor);

    for (final IProjectContributionEventListener listener : listeners) {
     
      execute(new SafeExecutableWithMonitor() {
       
        @SuppressWarnings("deprecation")
        public void execute(IProgressMonitor subMonitor) throws Exception {
          listener.finishContributor(validatorDefinition.getValidator(), affectedResources, subMonitor);
          listener.finishValidator(validatorDefinition, affectedResources, subMonitor);
        }
      }, monitor);
     
    }
  }

  protected IProgressMonitor createProgressMonitor(IProgressMonitor monitor) {
    return new SubProgressMonitor(monitor, 1);
  }

  protected void execute(final SafeExecutableWithMonitor executable, IProgressMonitor monitor) {
    final IProgressMonitor subMonitor = createProgressMonitor(monitor);

    ISafeRunnable code = new ISafeRunnable() {
      public void handleException(Throwable e) {
        // nothing to do - exception is already logged
      }

      public void run() throws Exception {
        executable.execute(subMonitor);
      }
    };
    SafeRunner.run(code);

    subMonitor.done();
  }

  protected interface SafeExecutableWithMonitor {

    void execute(IProgressMonitor monitor) throws Exception;

  }

  /**
   * Create a list of affected resources from a resource delta.
   */
  public static class ResourceDeltaVisitor implements IResourceDeltaVisitor {

    private IProjectContributor contributor;

    private int kind = -1;

    private Set<IResource> resources;

    public ResourceDeltaVisitor(IProjectContributor builder, int kind) {
      this.contributor = builder;
      this.resources = new LinkedHashSet<IResource>();
      this.kind = kind;
    }

    public Set<IResource> getResources() {
      return resources;
    }

    public boolean visit(IResourceDelta aDelta) throws CoreException {
      boolean visitChildren = false;

      IResource resource = aDelta.getResource();
      if (resource instanceof IProject) {

        // Only check projects with Spring beans nature
        visitChildren = SpringCoreUtils.isSpringProject(resource);
        if (visitChildren) {
          resources.addAll(contributor.getAffectedResources(resource, kind, aDelta.getKind()));
        }
      }
      else if (resource instanceof IFolder) {
        resources.addAll(contributor.getAffectedResources(resource, kind, aDelta.getKind()));
        visitChildren = true;
      }
      else if (resource instanceof IFile) {
        switch (aDelta.getKind()) {
        case IResourceDelta.ADDED:
        case IResourceDelta.CHANGED:
          resources.addAll(contributor.getAffectedResources(resource, kind, aDelta.getKind()));
          visitChildren = true;
          break;

        case IResourceDelta.REMOVED:
          resources.addAll(contributor.getAffectedResources(resource, kind, aDelta.getKind()));
          break;
        }
      }
      return visitChildren;
    }
  }

  /**
   * Create a list of affected resources from a resource tree.
   */
  public static class ResourceTreeVisitor implements IResourceVisitor {

    private IProjectContributor contributor;

    private Set<IResource> resources;

    public ResourceTreeVisitor(IProjectContributor builder) {
      this.contributor = builder;
      this.resources = new LinkedHashSet<IResource>();
    }

    public Set<IResource> getResources() {
      return resources;
    }

    public boolean visit(IResource resource) throws CoreException {
      if (resource instanceof IFile) {
        resources.addAll(contributor.getAffectedResources(resource, IncrementalProjectBuilder.FULL_BUILD,
            IResourceDelta.CHANGED));
      }
      else if (resource instanceof IProject) {
        resources.addAll(contributor.getAffectedResources(resource, IncrementalProjectBuilder.FULL_BUILD,
            IResourceDelta.CHANGED));
      }
      return true;
    }
  }
}
TOP

Related Classes of org.springframework.ide.eclipse.core.internal.project.SpringProjectContributionManager$ResourceTreeVisitor

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.