1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.core.builder;
12 import java.io.DataInputStream;
13 import java.io.DataOutputStream;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.Iterator;
20 import net.sourceforge.phpdt.core.IClasspathEntry;
21 import net.sourceforge.phpdt.core.IJavaModelMarker;
22 import net.sourceforge.phpdt.core.JavaModelException;
23 import net.sourceforge.phpdt.core.JavaCore;
24 import net.sourceforge.phpdt.core.compiler.CharOperation;
25 import net.sourceforge.phpdt.internal.core.JavaModel;
26 import net.sourceforge.phpdt.internal.core.JavaModelManager;
27 import net.sourceforge.phpdt.internal.core.JavaProject;
28 import net.sourceforge.phpdt.internal.core.Util;
29 import net.sourceforge.phpdt.internal.core.util.SimpleLookupTable;
30 import net.sourceforge.phpdt.internal.ui.util.PHPFileUtil;
31 import net.sourceforge.phpeclipse.PHPeclipsePlugin;
32 import net.sourceforge.phpeclipse.builder.IdentifierIndexManager;
33 import net.sourceforge.phpeclipse.phpeditor.PHPParserAction;
34 import net.sourceforge.phpeclipse.resourcesview.PHPProject;
35 import org.eclipse.core.resources.IFile;
36 import org.eclipse.core.resources.IMarker;
37 import org.eclipse.core.resources.IProject;
38 import org.eclipse.core.resources.IResource;
39 import org.eclipse.core.resources.IResourceChangeEvent;
40 import org.eclipse.core.resources.IResourceDelta;
41 import org.eclipse.core.resources.IResourceVisitor;
42 import org.eclipse.core.resources.IWorkspaceRoot;
43 import org.eclipse.core.resources.IncrementalProjectBuilder;
44 import org.eclipse.core.runtime.CoreException;
45 import org.eclipse.core.runtime.IPath;
46 import org.eclipse.core.runtime.IProgressMonitor;
47 import org.eclipse.core.runtime.OperationCanceledException;
48 public class PHPBuilder extends IncrementalProjectBuilder {
49 IProject currentProject;
50 JavaProject javaProject;
51 IWorkspaceRoot workspaceRoot;
52 NameEnvironment nameEnvironment;
53 SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary
54 // resources (output folders,
55 // class folders, zip/jar files)
57 BuildNotifier notifier;
58 char[][] extraResourceFileFilters;
59 String[] extraResourceFolderFilters;
60 public static final String CLASS_EXTENSION = "class"; //$NON-NLS-1$
61 public static boolean DEBUG = true;
63 * A list of project names that have been built. This list is used to reset
64 * the JavaModel.existingExternalFiles cache when a build cycle begins so
65 * that deleted external jars are discovered.
67 static ArrayList builtProjects = null;
68 public static IMarker[] getProblemsFor(IResource resource) {
70 if (resource != null && resource.exists())
71 return resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
72 false, IResource.DEPTH_INFINITE);
73 } catch (CoreException e) {
74 } // assume there are no problems
75 return new IMarker[0];
77 public static IMarker[] getTasksFor(IResource resource) {
79 if (resource != null && resource.exists())
80 return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false,
81 IResource.DEPTH_INFINITE);
82 } catch (CoreException e) {
83 } // assume there are no tasks
84 return new IMarker[0];
86 public static void finishedBuilding(IResourceChangeEvent event) {
87 BuildNotifier.resetProblemCounters();
89 public static void removeProblemsFor(IResource resource) {
91 if (resource != null && resource.exists())
92 resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
93 false, IResource.DEPTH_INFINITE);
94 } catch (CoreException e) {
95 } // assume there were no problems
97 public static void removeTasksFor(IResource resource) {
99 if (resource != null && resource.exists())
100 resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
101 IResource.DEPTH_INFINITE);
102 } catch (CoreException e) {
103 } // assume there were no problems
105 public static void removeProblemsAndTasksFor(IResource resource) {
107 if (resource != null && resource.exists()) {
108 resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER,
109 false, IResource.DEPTH_INFINITE);
110 resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false,
111 IResource.DEPTH_INFINITE);
113 } catch (CoreException e) {
114 } // assume there were no problems
116 public static State readState(IProject project, DataInputStream in)
118 return State.read(project, in);
120 public static void writeState(Object state, DataOutputStream out)
122 ((State) state).write(out);
124 public PHPBuilder() {
126 protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor)
127 throws CoreException {
128 this.currentProject = getProject();
129 if (currentProject == null || !currentProject.isAccessible())
130 return new IProject[0];
132 System.out.println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
133 + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
134 this.notifier = new BuildNotifier(monitor, currentProject);
138 notifier.checkCancel();
140 if (isWorthBuilding()) {
141 if (kind == FULL_BUILD) {
142 processFullPHPIndex(currentProject, monitor);
145 if ((this.lastState = getLastState(currentProject)) == null) {
148 .println("Performing full build since last saved state was not found"); //$NON-NLS-1$
149 processFullPHPIndex(currentProject, monitor);
151 // } else if (hasClasspathChanged()) {
152 // // if the output location changes, do not delete the binary files
153 // // from old location
154 // // the user may be trying something
156 } else if (nameEnvironment.sourceLocations.length > 0) {
157 // if there is no source to compile & no classpath changes then we
159 SimpleLookupTable deltas = findDeltas();
162 else if (deltas.elementSize > 0)
165 System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
167 if (hasStructuralDelta()) { // double check that a jar file didn't
168 // get replaced in a binary project
169 processFullPHPIndex(currentProject, monitor);
174 .println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
175 lastState.tagAsNoopBuild();
181 } catch (CoreException e) {
182 Util.log(e, "JavaBuilder handling CoreException"); //$NON-NLS-1$
183 IMarker marker = currentProject
184 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
185 marker.setAttribute(IMarker.MESSAGE, Util.bind(
186 "build.inconsistentProject", e.getLocalizedMessage())); //$NON-NLS-1$
187 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
188 } catch (ImageBuilderInternalException e) {
189 Util.log(e.getThrowable(),
190 "JavaBuilder handling ImageBuilderInternalException"); //$NON-NLS-1$
191 IMarker marker = currentProject
192 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
193 marker.setAttribute(IMarker.MESSAGE, Util.bind(
194 "build.inconsistentProject", e.coreException.getLocalizedMessage())); //$NON-NLS-1$
195 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
196 } catch (MissingClassFileException e) {
197 // do not log this exception since its thrown to handle aborted compiles
198 // because of missing class files
200 System.out.println(Util.bind("build.incompleteClassPath",
201 e.missingClassFile)); //$NON-NLS-1$
202 IMarker marker = currentProject
203 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
204 marker.setAttribute(IMarker.MESSAGE, Util.bind(
205 "build.incompleteClassPath", e.missingClassFile)); //$NON-NLS-1$
206 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
207 } catch (MissingSourceFileException e) {
208 // do not log this exception since its thrown to handle aborted compiles
209 // because of missing source files
211 System.out.println(Util.bind("build.missingSourceFile",
212 e.missingSourceFile)); //$NON-NLS-1$
213 removeProblemsAndTasksFor(currentProject); // make this the only problem
215 IMarker marker = currentProject
216 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
217 marker.setAttribute(IMarker.MESSAGE, Util.bind("build.missingSourceFile",
218 e.missingSourceFile)); //$NON-NLS-1$
219 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
222 // If the build failed, clear the previously built state, forcing a
223 // full build next time.
228 IProject[] requiredProjects = getRequiredProjects(true);
230 System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
231 + " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
232 return requiredProjects;
235 * Performs a <code>FULL_BUILD</code> by visiting all nodes in the resource
236 * tree under the specified project.
240 private void processFullPHPIndex(final IProject iProject,
241 final IProgressMonitor monitor) {
242 final IdentifierIndexManager indexManager = PHPeclipsePlugin.getDefault()
243 .getIndexManager(iProject);
244 // Create resource visitor logic
245 IResourceVisitor myVisitor = new IResourceVisitor() {
246 public boolean visit(IResource resource) throws CoreException {
247 if (resource.getType() == IResource.FILE) {
248 if (monitor.isCanceled()) {
249 throw new OperationCanceledException();
251 if ((resource.getFileExtension() != null)
252 && PHPFileUtil.isPHPFile((IFile) resource)) {
254 monitor.subTask("Parsing: " + resource.getFullPath());
255 // update indexfile for the project:
256 // PHPProject nature = (PHPProject) iProject
257 // .getNature(PHPeclipsePlugin.PHP_NATURE_ID);
258 indexManager.addFile((IFile) resource);
264 // Process the project using the visitor just created
266 // if (iProject.hasNature(PHPeclipsePlugin.PHP_NATURE_ID)) {
267 // thePHPProject = new PHPProject();
268 // thePHPProject.setProject(iProject);
270 indexManager.initialize();
271 iProject.accept(myVisitor);
272 indexManager.writeFile();
273 } catch (CoreException e) {
277 private void buildAll() {
278 notifier.checkCancel();
279 notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
280 if (DEBUG && lastState != null)
281 System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
283 BatchImageBuilder imageBuilder = new BatchImageBuilder(this);
284 imageBuilder.build();
285 recordNewState(imageBuilder.newState);
287 private void buildDeltas(SimpleLookupTable deltas) {
288 notifier.checkCancel();
289 notifier.subTask(Util.bind("build.preparingBuild")); //$NON-NLS-1$
290 if (DEBUG && lastState != null)
291 System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
292 clearLastState(); // clear the previously built state so if the build
293 // fails, a full build will occur next time
294 IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
295 if (imageBuilder.build(deltas))
296 recordNewState(imageBuilder.newState);
298 processFullPHPIndex(currentProject, notifier.monitor);
302 private void cleanup() {
303 this.nameEnvironment = null;
304 this.binaryLocationsPerProject = null;
305 this.lastState = null;
306 this.notifier = null;
307 this.extraResourceFileFilters = null;
308 this.extraResourceFolderFilters = null;
310 private void clearLastState() {
311 JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
314 boolean filterExtraResource(IResource resource) {
315 if (extraResourceFileFilters != null) {
316 char[] name = resource.getName().toCharArray();
317 for (int i = 0, l = extraResourceFileFilters.length; i < l; i++)
318 if (CharOperation.match(extraResourceFileFilters[i], name, true))
321 if (extraResourceFolderFilters != null) {
322 IPath path = resource.getProjectRelativePath();
323 String pathName = path.toString();
324 int count = path.segmentCount();
325 if (resource.getType() == IResource.FILE)
327 for (int i = 0, l = extraResourceFolderFilters.length; i < l; i++)
328 if (pathName.indexOf(extraResourceFolderFilters[i]) != -1)
329 for (int j = 0; j < count; j++)
330 if (extraResourceFolderFilters[i].equals(path.segment(j)))
335 private SimpleLookupTable findDeltas() {
336 notifier.subTask(Util.bind("build.readingDelta", currentProject.getName())); //$NON-NLS-1$
337 IResourceDelta delta = getDelta(currentProject);
338 SimpleLookupTable deltas = new SimpleLookupTable(3);
340 if (delta.getKind() != IResourceDelta.NO_CHANGE) {
342 System.out.println("Found source delta for: "
343 + currentProject.getName()); //$NON-NLS-1$
344 deltas.put(currentProject, delta);
348 System.out.println("Missing delta for: " + currentProject.getName()); //$NON-NLS-1$
349 notifier.subTask(""); //$NON-NLS-1$
352 Object[] keyTable = binaryLocationsPerProject.keyTable;
353 Object[] valueTable = binaryLocationsPerProject.valueTable;
354 nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
355 IProject p = (IProject) keyTable[i];
356 if (p != null && p != currentProject) {
357 State s = getLastState(p);
358 if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip
360 if (s.wasNoopBuild())
361 continue nextProject; // project has no source folders and can be
363 // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
365 boolean canSkip = true;
366 // for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
367 // if (classFoldersAndJars[j].isOutputFolder())
368 // classFoldersAndJars[j] = null; // can ignore output folder since
369 // project was not structurally changed
374 continue nextProject; // project has no structural changes in its
377 notifier.subTask(Util.bind("build.readingDelta", p.getName())); //$NON-NLS-1$
380 if (delta.getKind() != IResourceDelta.NO_CHANGE) {
382 System.out.println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
383 deltas.put(p, delta);
387 System.out.println("Missing delta for: " + p.getName()); //$NON-NLS-1$
388 notifier.subTask(""); //$NON-NLS-1$
393 notifier.subTask(""); //$NON-NLS-1$
396 private State getLastState(IProject project) {
397 return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(
398 project, notifier.monitor);
401 * Return the list of projects for which it requires a resource delta. This
402 * builder's project is implicitly included and need not be specified.
403 * Builders must re-specify the list of interesting projects every time they
404 * are run as this is not carried forward beyond the next build. Missing
405 * projects should be specified but will be ignored until they are added to
408 private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
409 if (javaProject == null || workspaceRoot == null)
410 return new IProject[0];
411 ArrayList projects = new ArrayList();
413 IClasspathEntry[] entries = javaProject.getExpandedClasspath(true);
414 for (int i = 0, l = entries.length; i < l; i++) {
415 IClasspathEntry entry = entries[i];
416 IPath path = entry.getPath();
418 switch (entry.getEntryKind()) {
419 case IClasspathEntry.CPE_PROJECT :
420 p = workspaceRoot.getProject(path.lastSegment()); // missing
424 case IClasspathEntry.CPE_LIBRARY :
425 if (includeBinaryPrerequisites && path.segmentCount() > 1) {
426 // some binary resources on the class path can come from projects
427 // that are not included in the project references
428 IResource resource = workspaceRoot.findMember(path.segment(0));
429 if (resource instanceof IProject)
430 p = (IProject) resource;
433 if (p != null && !projects.contains(p))
436 } catch (JavaModelException e) {
437 return new IProject[0];
439 IProject[] result = new IProject[projects.size()];
440 projects.toArray(result);
443 // private boolean hasClasspathChanged() {
444 // ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
445 // ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
446 // int newLength = newSourceLocations.length;
447 // int oldLength = oldSourceLocations.length;
449 // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
450 // if (newSourceLocations[n].equals(oldSourceLocations[o]))
451 // continue; // checks source & output folders
453 // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
461 // } catch (CoreException ignore) {
464 // System.out.println(newSourceLocations[n] + " != "
465 // + oldSourceLocations[o]); //$NON-NLS-1$
468 // while (n < newLength) {
470 // if (newSourceLocations[n].sourceFolder.members().length == 0) { // added
478 // } catch (CoreException ignore) {
481 // System.out.println("Added non-empty source folder"); //$NON-NLS-1$
484 // if (o < oldLength) {
486 // System.out.println("Removed source folder"); //$NON-NLS-1$
489 // // ClasspathLocation[] newBinaryLocations =
490 // // nameEnvironment.binaryLocations;
491 // // ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
492 // // newLength = newBinaryLocations.length;
493 // // oldLength = oldBinaryLocations.length;
494 // // for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
495 // // if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
497 // // System.out.println(newBinaryLocations[n] + " != " +
498 // // oldBinaryLocations[o]); //$NON-NLS-1$
501 // // if (n < newLength || o < oldLength) {
503 // // System.out.println("Number of binary folders/jar files has changed");
509 private boolean hasStructuralDelta() {
510 // handle case when currentProject has only .class file folders and/or jar
511 // files... no source/output folders
512 IResourceDelta delta = getDelta(currentProject);
513 if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
514 // ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[])
515 // binaryLocationsPerProject.get(currentProject);
516 // if (classFoldersAndJars != null) {
517 // for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
518 // ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either
519 // a .class file folder or a zip/jar file
520 // if (classFolderOrJar != null) {
521 // IPath p = classFolderOrJar.getProjectRelativePath();
523 // IResourceDelta binaryDelta = delta.findMember(p);
524 // if (binaryDelta != null && binaryDelta.getKind() !=
525 // IResourceDelta.NO_CHANGE)
534 private void initializeBuilder() throws CoreException {
535 this.javaProject = (JavaProject) JavaCore.create(currentProject);
536 this.workspaceRoot = currentProject.getWorkspace().getRoot();
537 // Flush the existing external files cache if this is the beginning of a
539 String projectName = currentProject.getName();
540 if (builtProjects == null || builtProjects.contains(projectName)) {
541 JavaModel.flushExternalFileCache();
542 builtProjects = new ArrayList();
544 builtProjects.add(projectName);
545 this.binaryLocationsPerProject = new SimpleLookupTable(3);
546 this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject,
547 binaryLocationsPerProject);
548 String filterSequence = javaProject.getOption(
549 JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
550 char[][] filters = filterSequence != null && filterSequence.length() > 0
551 ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
553 if (filters == null) {
554 this.extraResourceFileFilters = null;
555 this.extraResourceFolderFilters = null;
557 int fileCount = 0, folderCount = 0;
558 for (int i = 0, l = filters.length; i < l; i++) {
559 char[] f = filters[i];
562 if (f[f.length - 1] == '/')
567 this.extraResourceFileFilters = new char[fileCount][];
568 this.extraResourceFolderFilters = new String[folderCount];
569 for (int i = 0, l = filters.length; i < l; i++) {
570 char[] f = filters[i];
573 if (f[f.length - 1] == '/')
574 extraResourceFolderFilters[--folderCount] = new String(CharOperation
575 .subarray(f, 0, f.length - 1));
577 extraResourceFileFilters[--fileCount] = f;
581 private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p)
582 throws CoreException {
583 if (classpath == JavaProject.INVALID_CLASSPATH) // the .classpath file
586 IMarker[] markers = p.findMarkers(
587 IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
588 for (int i = 0, l = markers.length; i < l; i++)
589 if (((Integer) markers[i].getAttribute(IMarker.SEVERITY)).intValue() == IMarker.SEVERITY_ERROR)
593 private boolean isWorthBuilding() throws CoreException {
594 boolean abortBuilds = JavaCore.ABORT.equals(javaProject.getOption(
595 JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
598 // Abort build only if there are classpath errors
599 // if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
601 // System.out.println("Aborted build because project has classpath errors
602 // (incomplete or involved in cycle)"); //$NON-NLS-1$
604 // JavaModelManager.getJavaModelManager().deltaProcessor.addForRefresh(javaProject);
606 // removeProblemsAndTasksFor(currentProject); // remove all compilation
610 // currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
611 // marker.setAttribute(IMarker.MESSAGE,
612 // Util.bind("build.abortDueToClasspathProblems")); //$NON-NLS-1$
613 // marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
616 // make sure all prereq projects have valid build states... only when
617 // aborting builds since projects in cycles do not have build states
618 // except for projects involved in a 'warning' cycle (see below)
619 IProject[] requiredProjects = getRequiredProjects(false);
620 next : for (int i = 0, l = requiredProjects.length; i < l; i++) {
621 IProject p = requiredProjects[i];
622 if (getLastState(p) == null) {
623 // The prereq project has no build state: if this prereq project has a
624 // 'warning' cycle marker then allow build (see bug id 23357)
625 JavaProject prereq = (JavaProject) JavaCore.create(p);
626 if (prereq.hasCycleMarker()
627 && JavaCore.WARNING.equals(javaProject.getOption(
628 JavaCore.CORE_CIRCULAR_CLASSPATH, true)))
631 System.out.println("Aborted build because prereq project "
632 + p.getName() //$NON-NLS-1$
633 + " was not built"); //$NON-NLS-1$
634 removeProblemsAndTasksFor(currentProject); // make this the only
635 // problem for this project
636 IMarker marker = currentProject
637 .createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
638 marker.setAttribute(IMarker.MESSAGE, isClasspathBroken(prereq
639 .getRawClasspath(), p) ? Util.bind(
640 "build.prereqProjectHasClasspathProblems", p.getName()) //$NON-NLS-1$
641 : Util.bind("build.prereqProjectMustBeRebuilt", p.getName())); //$NON-NLS-1$
642 marker.setAttribute(IMarker.SEVERITY, IMarker.SEVERITY_ERROR);
649 * Instruct the build manager that this project is involved in a cycle and
650 * needs to propagate structural changes to the other projects in the cycle.
652 void mustPropagateStructuralChanges() {
653 HashSet cycleParticipants = new HashSet(3);
654 javaProject.updateCycleParticipants(null, new ArrayList(),
655 cycleParticipants, workspaceRoot, new HashSet(3));
656 IPath currentPath = javaProject.getPath();
657 Iterator i = cycleParticipants.iterator();
658 while (i.hasNext()) {
659 IPath participantPath = (IPath) i.next();
660 if (participantPath != currentPath) {
661 IProject project = this.workspaceRoot.getProject(participantPath
663 if (hasBeenBuilt(project)) {
666 .println("Requesting another build iteration since cycle participant "
667 + project.getName() //$NON-NLS-1$
668 + " has not yet seen some structural changes"); //$NON-NLS-1$
675 private void recordNewState(State state) {
676 Object[] keyTable = binaryLocationsPerProject.keyTable;
677 for (int i = 0, l = keyTable.length; i < l; i++) {
678 IProject prereqProject = (IProject) keyTable[i];
679 if (prereqProject != null && prereqProject != currentProject)
680 state.recordStructuralDependency(prereqProject,
681 getLastState(prereqProject));
684 System.out.println("Recording new state : " + state); //$NON-NLS-1$
686 JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject,
690 * String representation for debugging purposes
692 public String toString() {
693 return currentProject == null ? "JavaBuilder for unknown project" //$NON-NLS-1$
694 : "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$