Package org.eclipse.jdt.internal.core.builder

Source Code of org.eclipse.jdt.internal.core.builder.JavaBuilder

/*******************************************************************************
* 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*     IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.core.builder;

import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.*;

import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.compiler.*;
import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.jdt.internal.core.*;
import org.eclipse.jdt.internal.core.util.Messages;
import org.eclipse.jdt.internal.core.util.Util;

import java.io.*;
import java.util.*;

public class JavaBuilder extends IncrementalProjectBuilder {

IProject currentProject;
JavaProject javaProject;
IWorkspaceRoot workspaceRoot;
CompilationParticipant[] participants;
NameEnvironment nameEnvironment;
SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary resources (output folders, class folders, zip/jar files)
public State lastState;
BuildNotifier notifier;
char[][] extraResourceFileFilters;
String[] extraResourceFolderFilters;
public static final String SOURCE_ID = "JDT"; //$NON-NLS-1$

public static boolean DEBUG = false;
public static boolean SHOW_STATS = false;

/**
* A list of project names that have been built.
* This list is used to reset the JavaModel.existingExternalFiles cache when a build cycle begins
* so that deleted external jars are discovered.
*/
static ArrayList builtProjects = null;

public static IMarker[] getProblemsFor(IResource resource) {
  try {
    if (resource != null && resource.exists()) {
      IMarker[] markers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
      Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
      if (markerTypes.isEmpty()) return markers;
      ArrayList markerList = new ArrayList(5);
      for (int i = 0, length = markers.length; i < length; i++) {
        markerList.add(markers[i]);
      }
      Iterator iterator = markerTypes.iterator();
      while (iterator.hasNext()) {
        markers = resource.findMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
        for (int i = 0, length = markers.length; i < length; i++) {
          markerList.add(markers[i]);
        }
      }
      IMarker[] result;
      markerList.toArray(result = new IMarker[markerList.size()]);
      return result;
    }
  } catch (CoreException e) {
    // assume there are no problems
  }
  return new IMarker[0];
}

public static IMarker[] getTasksFor(IResource resource) {
  try {
    if (resource != null && resource.exists())
      return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
  } catch (CoreException e) {
    // assume there are no tasks
  }
  return new IMarker[0];
}

/**
* Hook allowing to initialize some static state before a complete build iteration.
* This hook is invoked during PRE_AUTO_BUILD notification
*/
public static void buildStarting() {
  // build is about to start
}

/**
* Hook allowing to reset some static state after a complete build iteration.
* This hook is invoked during POST_AUTO_BUILD notification
*/
public static void buildFinished() {
  BuildNotifier.resetProblemCounters();
}

public static void removeProblemsFor(IResource resource) {
  try {
    if (resource != null && resource.exists()) {
      resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);

      // delete managed markers
      Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
      if (markerTypes.size() == 0) return;
      Iterator iterator = markerTypes.iterator();
      while (iterator.hasNext())
        resource.deleteMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
    }
  } catch (CoreException e) {
    // assume there were no problems
  }
}

public static void removeTasksFor(IResource resource) {
  try {
    if (resource != null && resource.exists())
      resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
  } catch (CoreException e) {
    // assume there were no problems
  }
}

public static void removeProblemsAndTasksFor(IResource resource) {
  try {
    if (resource != null && resource.exists()) {
      resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
      resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);

      // delete managed markers
      Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
      if (markerTypes.size() == 0) return;
      Iterator iterator = markerTypes.iterator();
      while (iterator.hasNext())
        resource.deleteMarkers((String) iterator.next(), false, IResource.DEPTH_INFINITE);
    }
  } catch (CoreException e) {
    // assume there were no problems
  }
}

public static State readState(IProject project, DataInputStream in) throws IOException {
  return State.read(project, in);
}

public static void writeState(Object state, DataOutputStream out) throws IOException {
  ((State) state).write(out);
}

protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor) throws CoreException {
  this.currentProject = getProject();
  if (this.currentProject == null || !this.currentProject.isAccessible()) return new IProject[0];

  if (DEBUG)
    System.out.println("\nStarting build of " + this.currentProject.getName() //$NON-NLS-1$
      + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
  this.notifier = new BuildNotifier(monitor, this.currentProject);
  this.notifier.begin();
  boolean ok = false;
  try {
    this.notifier.checkCancel();
    kind = initializeBuilder(kind, true);

    if (isWorthBuilding()) {
      if (kind == FULL_BUILD) {
        if (DEBUG)
          System.out.println("Performing full build as requested by user"); //$NON-NLS-1$
        buildAll();
      } else {
        if ((this.lastState = getLastState(this.currentProject)) == null) {
          if (DEBUG)
            System.out.println("Performing full build since last saved state was not found"); //$NON-NLS-1$
          buildAll();
        } else if (hasClasspathChanged()) {
          // if the output location changes, do not delete the binary files from old location
          // the user may be trying something
          if (DEBUG)
            System.out.println("Performing full build since classpath has changed"); //$NON-NLS-1$
          buildAll();
        } else if (this.nameEnvironment.sourceLocations.length > 0) {
          // if there is no source to compile & no classpath changes then we are done
          SimpleLookupTable deltas = findDeltas();
          if (deltas == null) {
            if (DEBUG)
              System.out.println("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
            buildAll();
          } else if (deltas.elementSize > 0) {
            buildDeltas(deltas);
          } else if (DEBUG) {
            System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
          }
        } else {
          if (hasStructuralDelta()) { // double check that a jar file didn't get replaced in a binary project
            if (DEBUG)
              System.out.println("Performing full build since there are structural deltas"); //$NON-NLS-1$
            buildAll();
          } else {
            if (DEBUG)
              System.out.println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
            this.lastState.tagAsNoopBuild();
          }
        }
      }
      ok = true;
    }
  } catch (CoreException e) {
    Util.log(e, "JavaBuilder handling CoreException while building: " + this.currentProject.getName()); //$NON-NLS-1$
    createInconsistentBuildMarker(e);
  } catch (ImageBuilderInternalException e) {
    Util.log(e.getThrowable(), "JavaBuilder handling ImageBuilderInternalException while building: " + this.currentProject.getName()); //$NON-NLS-1$
    createInconsistentBuildMarker(e.coreException);
  } catch (MissingSourceFileException e) {
    // do not log this exception since its thrown to handle aborted compiles because of missing source files
    if (DEBUG)
      System.out.println(Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile));
    removeProblemsAndTasksFor(this.currentProject); // make this the only problem for this project
    IMarker marker = this.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
    marker.setAttributes(
      new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.SOURCE_ID},
      new Object[] {
        Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile),
        new Integer(IMarker.SEVERITY_ERROR),
        JavaBuilder.SOURCE_ID
      }
    );
  } finally {
    for (int i = 0, l = this.participants == null ? 0 : this.participants.length; i < l; i++)
      this.participants[i].buildFinished(this.javaProject);
    if (!ok)
      // If the build failed, clear the previously built state, forcing a full build next time.
      clearLastState();
    this.notifier.done();
    cleanup();
  }
  IProject[] requiredProjects = getRequiredProjects(true);
  if (DEBUG)
    System.out.println("Finished build of " + this.currentProject.getName() //$NON-NLS-1$
      + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
  return requiredProjects;
}

private void buildAll() {
  this.notifier.checkCancel();
  this.notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
  if (DEBUG && this.lastState != null)
    System.out.println("Clearing last state : " + this.lastState); //$NON-NLS-1$
  clearLastState();
  BatchImageBuilder imageBuilder = new BatchImageBuilder(this, true);
  imageBuilder.build();
  recordNewState(imageBuilder.newState);
}

private void buildDeltas(SimpleLookupTable deltas) {
  this.notifier.checkCancel();
  this.notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
  if (DEBUG && this.lastState != null)
    System.out.println("Clearing last state : " + this.lastState); //$NON-NLS-1$
  clearLastState(); // clear the previously built state so if the build fails, a full build will occur next time
  IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
  if (imageBuilder.build(deltas)) {
    recordNewState(imageBuilder.newState);
  } else {
    if (DEBUG)
      System.out.println("Performing full build since incremental build failed"); //$NON-NLS-1$
    buildAll();
  }
}

protected void clean(IProgressMonitor monitor) throws CoreException {
  this.currentProject = getProject();
  if (this.currentProject == null || !this.currentProject.isAccessible()) return;

  if (DEBUG)
    System.out.println("\nCleaning " + this.currentProject.getName() //$NON-NLS-1$
      + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
  this.notifier = new BuildNotifier(monitor, this.currentProject);
  this.notifier.begin();
  try {
    this.notifier.checkCancel();

    initializeBuilder(CLEAN_BUILD, true);
    if (DEBUG)
      System.out.println("Clearing last state as part of clean : " + this.lastState); //$NON-NLS-1$
    clearLastState();
    removeProblemsAndTasksFor(this.currentProject);
    new BatchImageBuilder(this, false).cleanOutputFolders(false);
  } catch (CoreException e) {
    Util.log(e, "JavaBuilder handling CoreException while cleaning: " + this.currentProject.getName()); //$NON-NLS-1$
    createInconsistentBuildMarker(e);
  } finally {
    this.notifier.done();
    cleanup();
  }
  if (DEBUG)
    System.out.println("Finished cleaning " + this.currentProject.getName() //$NON-NLS-1$
      + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
}

private void createInconsistentBuildMarker(CoreException coreException) throws CoreException {
  String message = null;
  IStatus status = coreException.getStatus();
   if (status.isMultiStatus()) {
     IStatus[] children = status.getChildren();
     if (children != null && children.length > 0)
         message = children[0].getMessage();
   }
   if (message == null)
     message = coreException.getMessage();

  IMarker marker = this.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
  marker.setAttributes(
    new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
    new Object[] {
      Messages.bind(Messages.build_inconsistentProject, message),
      new Integer(IMarker.SEVERITY_ERROR),
      new Integer(CategorizedProblem.CAT_BUILDPATH),
      JavaBuilder.SOURCE_ID
    }
  );
}

private void cleanup() {
  this.participants = null;
  this.nameEnvironment = null;
  this.binaryLocationsPerProject = null;
  this.lastState = null;
  this.notifier = null;
  this.extraResourceFileFilters = null;
  this.extraResourceFolderFilters = null;
}

private void clearLastState() {
  JavaModelManager.getJavaModelManager().setLastBuiltState(this.currentProject, null);
}

boolean filterExtraResource(IResource resource) {
  if (this.extraResourceFileFilters != null) {
    char[] name = resource.getName().toCharArray();
    for (int i = 0, l = this.extraResourceFileFilters.length; i < l; i++)
      if (CharOperation.match(this.extraResourceFileFilters[i], name, true))
        return true;
  }
  if (this.extraResourceFolderFilters != null) {
    IPath path = resource.getProjectRelativePath();
    String pathName = path.toString();
    int count = path.segmentCount();
    if (resource.getType() == IResource.FILE) count--;
    for (int i = 0, l = this.extraResourceFolderFilters.length; i < l; i++)
      if (pathName.indexOf(this.extraResourceFolderFilters[i]) != -1)
        for (int j = 0; j < count; j++)
          if (this.extraResourceFolderFilters[i].equals(path.segment(j)))
            return true;
  }
  return false;
}

private SimpleLookupTable findDeltas() {
  this.notifier.subTask(Messages.bind(Messages.build_readingDelta, this.currentProject.getName()));
  IResourceDelta delta = getDelta(this.currentProject);
  SimpleLookupTable deltas = new SimpleLookupTable(3);
  if (delta != null) {
    if (delta.getKind() != IResourceDelta.NO_CHANGE) {
      if (DEBUG)
        System.out.println("Found source delta for: " + this.currentProject.getName()); //$NON-NLS-1$
      deltas.put(this.currentProject, delta);
    }
  } else {
    if (DEBUG)
      System.out.println("Missing delta for: " + this.currentProject.getName()); //$NON-NLS-1$
    this.notifier.subTask(""); //$NON-NLS-1$
    return null;
  }

  Object[] keyTable = this.binaryLocationsPerProject.keyTable;
  Object[] valueTable = this.binaryLocationsPerProject.valueTable;
  nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
    IProject p = (IProject) keyTable[i];
    if (p != null && p != this.currentProject) {
      State s = getLastState(p);
      if (!this.lastState.wasStructurallyChanged(p, s)) { // see if we can skip its delta
        if (s.wasNoopBuild())
          continue nextProject; // project has no source folders and can be skipped
        ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) valueTable[i];
        boolean canSkip = true;
        for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
          if (classFoldersAndJars[j].isOutputFolder())
            classFoldersAndJars[j] = null; // can ignore output folder since project was not structurally changed
          else
            canSkip = false;
        }
        if (canSkip) continue nextProject; // project has no structural changes in its output folders
      }

      this.notifier.subTask(Messages.bind(Messages.build_readingDelta, p.getName()));
      delta = getDelta(p);
      if (delta != null) {
        if (delta.getKind() != IResourceDelta.NO_CHANGE) {
          if (DEBUG)
            System.out.println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
          deltas.put(p, delta);
        }
      } else {
        if (DEBUG)
          System.out.println("Missing delta for: " + p.getName());   //$NON-NLS-1$
        this.notifier.subTask(""); //$NON-NLS-1$
        return null;
      }
    }
  }
  this.notifier.subTask(""); //$NON-NLS-1$
  return deltas;
}

public State getLastState(IProject project) {
  return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(project, this.notifier.monitor);
}

/* Return the list of projects for which it requires a resource delta. This builder's project
* is implicitly included and need not be specified. Builders must re-specify the list
* of interesting projects every time they are run as this is not carried forward
* beyond the next build. Missing projects should be specified but will be ignored until
* they are added to the workspace.
*/
private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
  if (this.javaProject == null || this.workspaceRoot == null) return new IProject[0];

  ArrayList projects = new ArrayList();
  ExternalFoldersManager externalFoldersManager = JavaModelManager.getExternalManager();
  try {
    IClasspathEntry[] entries = this.javaProject.getExpandedClasspath();
    for (int i = 0, l = entries.length; i < l; i++) {
      IClasspathEntry entry = entries[i];
      IPath path = entry.getPath();
      IProject p = null;
      switch (entry.getEntryKind()) {
        case IClasspathEntry.CPE_PROJECT :
          p = this.workspaceRoot.getProject(path.lastSegment()); // missing projects are considered too
          if (((ClasspathEntry) entry).isOptional() && !JavaProject.hasJavaNature(p)) // except if entry is optional
            p = null;
          break;
        case IClasspathEntry.CPE_LIBRARY :
          if (includeBinaryPrerequisites && path.segmentCount() > 0) {
            // some binary resources on the class path can come from projects that are not included in the project references
            IResource resource = this.workspaceRoot.findMember(path.segment(0));
            if (resource instanceof IProject) {
              p = (IProject) resource;
            } else {
              resource = externalFoldersManager.getFolder(path);
              if (resource != null)
                p = resource.getProject();
            }
          }
      }
      if (p != null && !projects.contains(p))
        projects.add(p);
    }
  } catch(JavaModelException e) {
    return new IProject[0];
  }
  IProject[] result = new IProject[projects.size()];
  projects.toArray(result);
  return result;
}

boolean hasBuildpathErrors() throws CoreException {
  IMarker[] markers = this.currentProject.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
  for (int i = 0, l = markers.length; i < l; i++)
    if (markers[i].getAttribute(IJavaModelMarker.CATEGORY_ID, -1) == CategorizedProblem.CAT_BUILDPATH)
      return true;
  return false;
}

private boolean hasClasspathChanged() {
  ClasspathMultiDirectory[] newSourceLocations = this.nameEnvironment.sourceLocations;
  ClasspathMultiDirectory[] oldSourceLocations = this.lastState.sourceLocations;
  int newLength = newSourceLocations.length;
  int oldLength = oldSourceLocations.length;
  int n, o;
  for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
    if (newSourceLocations[n].equals(oldSourceLocations[o])) continue; // checks source & output folders
    try {
      if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
        o--;
        continue;
      } else if (this.lastState.isSourceFolderEmpty(oldSourceLocations[o].sourceFolder)) {
        n--;
        continue;
      }
    } catch (CoreException ignore) { // skip it
    }
    if (DEBUG) {
      System.out.println("New location: " + newSourceLocations[n] + "\n!= old location: " + oldSourceLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
      printLocations(newSourceLocations, oldSourceLocations);
    }
    return true;
  }
  while (n < newLength) {
    try {
      if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
        n++;
        continue;
      }
    } catch (CoreException ignore) { // skip it
    }
    if (DEBUG) {
      System.out.println("Added non-empty source folder"); //$NON-NLS-1$
      printLocations(newSourceLocations, oldSourceLocations);
    }
    return true;
  }
  while (o < oldLength) {
    if (this.lastState.isSourceFolderEmpty(oldSourceLocations[o].sourceFolder)) {
      o++;
      continue;
    }
    if (DEBUG) {
      System.out.println("Removed non-empty source folder"); //$NON-NLS-1$
      printLocations(newSourceLocations, oldSourceLocations);
    }
    return true;
  }

  ClasspathLocation[] newBinaryLocations = this.nameEnvironment.binaryLocations;
  ClasspathLocation[] oldBinaryLocations = this.lastState.binaryLocations;
  newLength = newBinaryLocations.length;
  oldLength = oldBinaryLocations.length;
  for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
    if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
    if (DEBUG) {
      System.out.println("New location: " + newBinaryLocations[n] + "\n!= old location: " + oldBinaryLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
      printLocations(newBinaryLocations, oldBinaryLocations);
    }
    return true;
  }
  if (n < newLength || o < oldLength) {
    if (DEBUG) {
      System.out.println("Number of binary folders/jar files has changed:"); //$NON-NLS-1$
      printLocations(newBinaryLocations, oldBinaryLocations);
    }
    return true;
  }
  return false;
}

private boolean hasJavaBuilder(IProject project) throws CoreException {
  ICommand[] buildCommands = project.getDescription().getBuildSpec();
  for (int i = 0, l = buildCommands.length; i < l; i++)
    if (buildCommands[i].getBuilderName().equals(JavaCore.BUILDER_ID))
      return true;
  return false;
}

private boolean hasStructuralDelta() {
  // handle case when currentProject has only .class file folders and/or jar files... no source/output folders
  IResourceDelta delta = getDelta(this.currentProject);
  if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
    ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) this.binaryLocationsPerProject.get(this.currentProject);
    if (classFoldersAndJars != null) {
      for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
        ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either a .class file folder or a zip/jar file
        if (classFolderOrJar != null) {
          IPath p = classFolderOrJar.getProjectRelativePath();
          if (p != null) {
            IResourceDelta binaryDelta = delta.findMember(p);
            if (binaryDelta != null && binaryDelta.getKind() != IResourceDelta.NO_CHANGE)
              return true;
          }
        }
      }
    }
  }
  return false;
}

private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
  // some calls just need the nameEnvironment initialized so skip the rest
  this.javaProject = (JavaProject) JavaCore.create(this.currentProject);
  this.workspaceRoot = this.currentProject.getWorkspace().getRoot();

  if (forBuild) {
    // cache the known participants for this project
    this.participants = JavaModelManager.getJavaModelManager().compilationParticipants.getCompilationParticipants(this.javaProject);
    if (this.participants != null)
      for (int i = 0, l = this.participants.length; i < l; i++)
        if (this.participants[i].aboutToBuild(this.javaProject) == CompilationParticipant.NEEDS_FULL_BUILD)
          kind = FULL_BUILD;

    // Flush the existing external files cache if this is the beginning of a build cycle
    String projectName = this.currentProject.getName();
    if (builtProjects == null || builtProjects.contains(projectName)) {
      JavaModel.flushExternalFileCache();
      builtProjects = new ArrayList();
    }
    builtProjects.add(projectName);
  }

  this.binaryLocationsPerProject = new SimpleLookupTable(3);
  this.nameEnvironment = new NameEnvironment(this.workspaceRoot, this.javaProject, this.binaryLocationsPerProject, this.notifier);

  if (forBuild) {
    String filterSequence = this.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
    char[][] filters = filterSequence != null && filterSequence.length() > 0
      ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
      : null;
    if (filters == null) {
      this.extraResourceFileFilters = null;
      this.extraResourceFolderFilters = null;
    } else {
      int fileCount = 0, folderCount = 0;
      for (int i = 0, l = filters.length; i < l; i++) {
        char[] f = filters[i];
        if (f.length == 0) continue;
        if (f[f.length - 1] == '/') folderCount++; else fileCount++;
      }
      this.extraResourceFileFilters = new char[fileCount][];
      this.extraResourceFolderFilters = new String[folderCount];
      for (int i = 0, l = filters.length; i < l; i++) {
        char[] f = filters[i];
        if (f.length == 0) continue;
        if (f[f.length - 1] == '/')
          this.extraResourceFolderFilters[--folderCount] = new String(f, 0, f.length - 1);
        else
          this.extraResourceFileFilters[--fileCount] = f;
      }
    }
  }
  return kind;
}

private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p) throws CoreException {
  IMarker[] markers = p.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
  for (int i = 0, l = markers.length; i < l; i++)
    if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
      return true;
  return false;
}

private boolean isWorthBuilding() throws CoreException {
  boolean abortBuilds =
    JavaCore.ABORT.equals(this.javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
  if (!abortBuilds) return true;

  // Abort build only if there are classpath errors
  if (isClasspathBroken(this.javaProject.getRawClasspath(), this.currentProject)) {
    if (DEBUG)
      System.out.println("Aborted build because project has classpath errors (incomplete or involved in cycle)"); //$NON-NLS-1$

    removeProblemsAndTasksFor(this.currentProject); // remove all compilation problems

    IMarker marker = this.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
    marker.setAttributes(
      new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
      new Object[] {
        Messages.build_abortDueToClasspathProblems,
        new Integer(IMarker.SEVERITY_ERROR),
        new Integer(CategorizedProblem.CAT_BUILDPATH),
        JavaBuilder.SOURCE_ID
      }
    );
    return false;
  }

  if (JavaCore.WARNING.equals(this.javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)))
    return true;

  // make sure all prereq projects have valid build states... only when aborting builds since projects in cycles do not have build states
  // except for projects involved in a 'warning' cycle (see below)
  IProject[] requiredProjects = getRequiredProjects(false);
  for (int i = 0, l = requiredProjects.length; i < l; i++) {
    IProject p = requiredProjects[i];
    if (getLastState(p) == null)  {
      // The prereq project has no build state: if this prereq project has a 'warning' cycle marker then allow build (see bug id 23357)
      JavaProject prereq = (JavaProject) JavaCore.create(p);
      if (prereq.hasCycleMarker() && JavaCore.WARNING.equals(this.javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
        if (DEBUG)
          System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
            + " was not built since its part of a cycle"); //$NON-NLS-1$
        continue;
      }
      if (!hasJavaBuilder(p)) {
        if (DEBUG)
          System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
            + " is not built by JavaBuilder"); //$NON-NLS-1$
        continue;
      }
      if (DEBUG)
        System.out.println("Aborted build because prereq project " + p.getName() //$NON-NLS-1$
          + " was not built"); //$NON-NLS-1$

      removeProblemsAndTasksFor(this.currentProject); // make this the only problem for this project
      IMarker marker = this.currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
      marker.setAttributes(
        new String[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
        new Object[] {
          isClasspathBroken(prereq.getRawClasspath(), p)
            ? Messages.bind(Messages.build_prereqProjectHasClasspathProblems, p.getName())
            : Messages.bind(Messages.build_prereqProjectMustBeRebuilt, p.getName()),
          new Integer(IMarker.SEVERITY_ERROR),
          new Integer(CategorizedProblem.CAT_BUILDPATH),
          JavaBuilder.SOURCE_ID
        }
      );
      return false;
    }
  }
  return true;
}

/*
* Instruct the build manager that this project is involved in a cycle and
* needs to propagate structural changes to the other projects in the cycle.
*/
void mustPropagateStructuralChanges() {
  LinkedHashSet cycleParticipants = new LinkedHashSet(3);
  this.javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, this.workspaceRoot, new HashSet(3), null);
  IPath currentPath = this.javaProject.getPath();
  Iterator i= cycleParticipants.iterator();
  while (i.hasNext()) {
    IPath participantPath = (IPath) i.next();
    if (participantPath != currentPath) {
      IProject project = this.workspaceRoot.getProject(participantPath.segment(0));
      if (hasBeenBuilt(project)) {
        if (DEBUG)
          System.out.println("Requesting another build iteration since cycle participant " + project.getName() //$NON-NLS-1$
            + " has not yet seen some structural changes"); //$NON-NLS-1$
        needRebuild();
        return;
      }
    }
  }
}

private void printLocations(ClasspathLocation[] newLocations, ClasspathLocation[] oldLocations) {
  System.out.println("New locations:"); //$NON-NLS-1$
  for (int i = 0, length = newLocations.length; i < length; i++)
    System.out.println("    " + newLocations[i].debugPathString()); //$NON-NLS-1$
  System.out.println("Old locations:"); //$NON-NLS-1$
  for (int i = 0, length = oldLocations.length; i < length; i++)
    System.out.println("    " + oldLocations[i].debugPathString()); //$NON-NLS-1$
}

private void recordNewState(State state) {
  Object[] keyTable = this.binaryLocationsPerProject.keyTable;
  for (int i = 0, l = keyTable.length; i < l; i++) {
    IProject prereqProject = (IProject) keyTable[i];
    if (prereqProject != null && prereqProject != this.currentProject)
      state.recordStructuralDependency(prereqProject, getLastState(prereqProject));
  }

  if (DEBUG)
    System.out.println("Recording new state : " + state); //$NON-NLS-1$
  // state.dump();
  JavaModelManager.getJavaModelManager().setLastBuiltState(this.currentProject, state);
}

/**
* String representation for debugging purposes
*/
public String toString() {
  return this.currentProject == null
    ? "JavaBuilder for unknown project" //$NON-NLS-1$
    : "JavaBuilder for " + this.currentProject.getName(); //$NON-NLS-1$
}
}
TOP

Related Classes of org.eclipse.jdt.internal.core.builder.JavaBuilder

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.