KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > builder > JavaBuilder


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.core.builder;
12
13 import org.eclipse.core.resources.*;
14 import org.eclipse.core.runtime.*;
15
16 import org.eclipse.jdt.core.*;
17 import org.eclipse.jdt.core.compiler.*;
18 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
19 import org.eclipse.jdt.internal.core.*;
20 import org.eclipse.jdt.internal.core.util.Messages;
21 import org.eclipse.jdt.internal.core.util.Util;
22
23 import java.io.*;
24 import java.util.*;
25
26 public class JavaBuilder extends IncrementalProjectBuilder {
27
28 IProject currentProject;
29 JavaProject javaProject;
30 IWorkspaceRoot workspaceRoot;
31 CompilationParticipant[] participants;
32 NameEnvironment nameEnvironment;
33 SimpleLookupTable binaryLocationsPerProject; // maps a project to its binary resources (output folders, class folders, zip/jar files)
34
public State lastState;
35 BuildNotifier notifier;
36 char[][] extraResourceFileFilters;
37 String JavaDoc[] extraResourceFolderFilters;
38 public static final String JavaDoc SOURCE_ID = "JDT"; //$NON-NLS-1$
39

40 public static boolean DEBUG = false;
41
42 /**
43  * A list of project names that have been built.
44  * This list is used to reset the JavaModel.existingExternalFiles cache when a build cycle begins
45  * so that deleted external jars are discovered.
46  */

47 static ArrayList builtProjects = null;
48
49 public static IMarker[] getProblemsFor(IResource resource) {
50     try {
51         if (resource != null && resource.exists()) {
52             IMarker[] markers = resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
53             Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
54             if (markerTypes.isEmpty()) return markers;
55             ArrayList markerList = new ArrayList(5);
56             for (int i = 0, length = markers.length; i < length; i++) {
57                 markerList.add(markers[i]);
58             }
59             Iterator iterator = markerTypes.iterator();
60             while (iterator.hasNext()) {
61                 markers = resource.findMarkers((String JavaDoc) iterator.next(), false, IResource.DEPTH_INFINITE);
62                 for (int i = 0, length = markers.length; i < length; i++) {
63                     markerList.add(markers[i]);
64                 }
65             }
66             IMarker[] result;
67             markerList.toArray(result = new IMarker[markerList.size()]);
68             return result;
69         }
70     } catch (CoreException e) {
71         // assume there are no problems
72
}
73     return new IMarker[0];
74 }
75
76 public static IMarker[] getTasksFor(IResource resource) {
77     try {
78         if (resource != null && resource.exists())
79             return resource.findMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
80     } catch (CoreException e) {
81         // assume there are no tasks
82
}
83     return new IMarker[0];
84 }
85
86 /**
87  * Hook allowing to initialize some static state before a complete build iteration.
88  * This hook is invoked during PRE_AUTO_BUILD notification
89  */

90 public static void buildStarting() {
91     // build is about to start
92
}
93
94 /**
95  * Hook allowing to reset some static state after a complete build iteration.
96  * This hook is invoked during POST_AUTO_BUILD notification
97  */

98 public static void buildFinished() {
99     BuildNotifier.resetProblemCounters();
100 }
101
102 public static void removeProblemsFor(IResource resource) {
103     try {
104         if (resource != null && resource.exists()) {
105             resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
106
107             // delete managed markers
108
Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
109             if (markerTypes.size() == 0) return;
110             Iterator iterator = markerTypes.iterator();
111             while (iterator.hasNext())
112                 resource.deleteMarkers((String JavaDoc) iterator.next(), false, IResource.DEPTH_INFINITE);
113         }
114     } catch (CoreException e) {
115         // assume there were no problems
116
}
117 }
118
119 public static void removeTasksFor(IResource resource) {
120     try {
121         if (resource != null && resource.exists())
122             resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
123     } catch (CoreException e) {
124         // assume there were no problems
125
}
126 }
127
128 public static void removeProblemsAndTasksFor(IResource resource) {
129     try {
130         if (resource != null && resource.exists()) {
131             resource.deleteMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_INFINITE);
132             resource.deleteMarkers(IJavaModelMarker.TASK_MARKER, false, IResource.DEPTH_INFINITE);
133
134             // delete managed markers
135
Set markerTypes = JavaModelManager.getJavaModelManager().compilationParticipants.managedMarkerTypes();
136             if (markerTypes.size() == 0) return;
137             Iterator iterator = markerTypes.iterator();
138             while (iterator.hasNext())
139                 resource.deleteMarkers((String JavaDoc) iterator.next(), false, IResource.DEPTH_INFINITE);
140         }
141     } catch (CoreException e) {
142         // assume there were no problems
143
}
144 }
145
146 public static State readState(IProject project, DataInputStream in) throws IOException {
147     return State.read(project, in);
148 }
149
150 public static void writeState(Object JavaDoc state, DataOutputStream out) throws IOException {
151     ((State) state).write(out);
152 }
153
154 protected IProject[] build(int kind, Map ignored, IProgressMonitor monitor) throws CoreException {
155     this.currentProject = getProject();
156     if (currentProject == null || !currentProject.isAccessible()) return new IProject[0];
157
158     if (DEBUG)
159         System.out.println("\nStarting build of " + currentProject.getName() //$NON-NLS-1$
160
+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
161
this.notifier = new BuildNotifier(monitor, currentProject);
162     notifier.begin();
163     boolean ok = false;
164     try {
165         notifier.checkCancel();
166         kind = initializeBuilder(kind, true);
167
168         if (isWorthBuilding()) {
169             if (kind == FULL_BUILD) {
170                 if (DEBUG)
171                     System.out.println("Performing full build as requested by user"); //$NON-NLS-1$
172
buildAll();
173             } else {
174                 if ((this.lastState = getLastState(currentProject)) == null) {
175                     if (DEBUG)
176                         System.out.println("Performing full build since last saved state was not found"); //$NON-NLS-1$
177
buildAll();
178                 } else if (hasClasspathChanged()) {
179                     // if the output location changes, do not delete the binary files from old location
180
// the user may be trying something
181
if (DEBUG)
182                         System.out.println("Performing full build since classpath has changed"); //$NON-NLS-1$
183
buildAll();
184                 } else if (nameEnvironment.sourceLocations.length > 0) {
185                     // if there is no source to compile & no classpath changes then we are done
186
SimpleLookupTable deltas = findDeltas();
187                     if (deltas == null) {
188                         if (DEBUG)
189                             System.out.println("Performing full build since deltas are missing after incremental request"); //$NON-NLS-1$
190
buildAll();
191                     } else if (deltas.elementSize > 0) {
192                         buildDeltas(deltas);
193                     } else if (DEBUG) {
194                         System.out.println("Nothing to build since deltas were empty"); //$NON-NLS-1$
195
}
196                 } else {
197                     if (hasStructuralDelta()) { // double check that a jar file didn't get replaced in a binary project
198
if (DEBUG)
199                             System.out.println("Performing full build since there are structural deltas"); //$NON-NLS-1$
200
buildAll();
201                     } else {
202                         if (DEBUG)
203                             System.out.println("Nothing to build since there are no source folders and no deltas"); //$NON-NLS-1$
204
lastState.tagAsNoopBuild();
205                     }
206                 }
207             }
208             ok = true;
209         }
210     } catch (CoreException e) {
211         Util.log(e, "JavaBuilder handling CoreException while building: " + currentProject.getName()); //$NON-NLS-1$
212
IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
213         marker.setAttributes(
214             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
215             new Object JavaDoc[] {
216                 Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
217                 new Integer JavaDoc(IMarker.SEVERITY_ERROR),
218                 new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
219                 JavaBuilder.SOURCE_ID
220             }
221         );
222     } catch (ImageBuilderInternalException e) {
223         Util.log(e.getThrowable(), "JavaBuilder handling ImageBuilderInternalException while building: " + currentProject.getName()); //$NON-NLS-1$
224
IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
225         marker.setAttributes(
226             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
227             new Object JavaDoc[] {
228                 Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
229                 new Integer JavaDoc(IMarker.SEVERITY_ERROR),
230                 new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
231                 JavaBuilder.SOURCE_ID
232             }
233         );
234     } catch (MissingSourceFileException e) {
235         // do not log this exception since its thrown to handle aborted compiles because of missing source files
236
if (DEBUG)
237             System.out.println(Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile));
238         removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
239
IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
240         marker.setAttributes(
241             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.SOURCE_ID},
242             new Object JavaDoc[] {
243                 Messages.bind(Messages.build_missingSourceFile, e.missingSourceFile),
244                 new Integer JavaDoc(IMarker.SEVERITY_ERROR),
245                 JavaBuilder.SOURCE_ID
246             }
247         );
248     } finally {
249         if (!ok)
250             // If the build failed, clear the previously built state, forcing a full build next time.
251
clearLastState();
252         notifier.done();
253         cleanup();
254     }
255     IProject[] requiredProjects = getRequiredProjects(true);
256     if (DEBUG)
257         System.out.println("Finished build of " + currentProject.getName() //$NON-NLS-1$
258
+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
259
return requiredProjects;
260 }
261
262 private void buildAll() {
263     notifier.checkCancel();
264     notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
265     if (DEBUG && lastState != null)
266         System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
267
clearLastState();
268     BatchImageBuilder imageBuilder = new BatchImageBuilder(this, true);
269     imageBuilder.build();
270     recordNewState(imageBuilder.newState);
271 }
272
273 private void buildDeltas(SimpleLookupTable deltas) {
274     notifier.checkCancel();
275     notifier.subTask(Messages.bind(Messages.build_preparingBuild, this.currentProject.getName()));
276     if (DEBUG && lastState != null)
277         System.out.println("Clearing last state : " + lastState); //$NON-NLS-1$
278
clearLastState(); // clear the previously built state so if the build fails, a full build will occur next time
279
IncrementalImageBuilder imageBuilder = new IncrementalImageBuilder(this);
280     if (imageBuilder.build(deltas)) {
281         recordNewState(imageBuilder.newState);
282     } else {
283         if (DEBUG)
284             System.out.println("Performing full build since incremental build failed"); //$NON-NLS-1$
285
buildAll();
286     }
287 }
288
289 protected void clean(IProgressMonitor monitor) throws CoreException {
290     this.currentProject = getProject();
291     if (currentProject == null || !currentProject.isAccessible()) return;
292
293     if (DEBUG)
294         System.out.println("\nCleaning " + currentProject.getName() //$NON-NLS-1$
295
+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
296
this.notifier = new BuildNotifier(monitor, currentProject);
297     notifier.begin();
298     try {
299         notifier.checkCancel();
300
301         initializeBuilder(CLEAN_BUILD, true);
302         if (DEBUG)
303             System.out.println("Clearing last state as part of clean : " + lastState); //$NON-NLS-1$
304
clearLastState();
305         removeProblemsAndTasksFor(currentProject);
306         new BatchImageBuilder(this, false).cleanOutputFolders(false);
307     } catch (CoreException e) {
308         Util.log(e, "JavaBuilder handling CoreException while cleaning: " + currentProject.getName()); //$NON-NLS-1$
309
IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
310         marker.setAttributes(
311             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IMarker.SOURCE_ID},
312             new Object JavaDoc[] {
313                 Messages.bind(Messages.build_inconsistentProject, e.getLocalizedMessage()),
314                 new Integer JavaDoc(IMarker.SEVERITY_ERROR),
315                 JavaBuilder.SOURCE_ID
316             }
317         );
318     } finally {
319         notifier.done();
320         cleanup();
321     }
322     if (DEBUG)
323         System.out.println("Finished cleaning " + currentProject.getName() //$NON-NLS-1$
324
+ " @ " + new Date(System.currentTimeMillis())); //$NON-NLS-1$
325
}
326
327 private void cleanup() {
328     this.participants = null;
329     this.nameEnvironment = null;
330     this.binaryLocationsPerProject = null;
331     this.lastState = null;
332     this.notifier = null;
333     this.extraResourceFileFilters = null;
334     this.extraResourceFolderFilters = null;
335 }
336
337 private void clearLastState() {
338     JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject, null);
339 }
340
341 boolean filterExtraResource(IResource resource) {
342     if (extraResourceFileFilters != null) {
343         char[] name = resource.getName().toCharArray();
344         for (int i = 0, l = extraResourceFileFilters.length; i < l; i++)
345             if (CharOperation.match(extraResourceFileFilters[i], name, true))
346                 return true;
347     }
348     if (extraResourceFolderFilters != null) {
349         IPath path = resource.getProjectRelativePath();
350         String JavaDoc pathName = path.toString();
351         int count = path.segmentCount();
352         if (resource.getType() == IResource.FILE) count--;
353         for (int i = 0, l = extraResourceFolderFilters.length; i < l; i++)
354             if (pathName.indexOf(extraResourceFolderFilters[i]) != -1)
355                 for (int j = 0; j < count; j++)
356                     if (extraResourceFolderFilters[i].equals(path.segment(j)))
357                         return true;
358     }
359     return false;
360 }
361
362 private SimpleLookupTable findDeltas() {
363     notifier.subTask(Messages.bind(Messages.build_readingDelta, currentProject.getName()));
364     IResourceDelta delta = getDelta(currentProject);
365     SimpleLookupTable deltas = new SimpleLookupTable(3);
366     if (delta != null) {
367         if (delta.getKind() != IResourceDelta.NO_CHANGE) {
368             if (DEBUG)
369                 System.out.println("Found source delta for: " + currentProject.getName()); //$NON-NLS-1$
370
deltas.put(currentProject, delta);
371         }
372     } else {
373         if (DEBUG)
374             System.out.println("Missing delta for: " + currentProject.getName()); //$NON-NLS-1$
375
notifier.subTask(""); //$NON-NLS-1$
376
return null;
377     }
378
379     Object JavaDoc[] keyTable = binaryLocationsPerProject.keyTable;
380     Object JavaDoc[] valueTable = binaryLocationsPerProject.valueTable;
381     nextProject : for (int i = 0, l = keyTable.length; i < l; i++) {
382         IProject p = (IProject) keyTable[i];
383         if (p != null && p != currentProject) {
384             State s = getLastState(p);
385             if (!lastState.wasStructurallyChanged(p, s)) { // see if we can skip its delta
386
if (s.wasNoopBuild())
387                     continue nextProject; // project has no source folders and can be skipped
388
ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) valueTable[i];
389                 boolean canSkip = true;
390                 for (int j = 0, m = classFoldersAndJars.length; j < m; j++) {
391                     if (classFoldersAndJars[j].isOutputFolder())
392                         classFoldersAndJars[j] = null; // can ignore output folder since project was not structurally changed
393
else
394                         canSkip = false;
395                 }
396                 if (canSkip) continue nextProject; // project has no structural changes in its output folders
397
}
398
399             notifier.subTask(Messages.bind(Messages.build_readingDelta, p.getName()));
400             delta = getDelta(p);
401             if (delta != null) {
402                 if (delta.getKind() != IResourceDelta.NO_CHANGE) {
403                     if (DEBUG)
404                         System.out.println("Found binary delta for: " + p.getName()); //$NON-NLS-1$
405
deltas.put(p, delta);
406                 }
407             } else {
408                 if (DEBUG)
409                     System.out.println("Missing delta for: " + p.getName()); //$NON-NLS-1$
410
notifier.subTask(""); //$NON-NLS-1$
411
return null;
412             }
413         }
414     }
415     notifier.subTask(""); //$NON-NLS-1$
416
return deltas;
417 }
418
419 public State getLastState(IProject project) {
420     return (State) JavaModelManager.getJavaModelManager().getLastBuiltState(project, notifier.monitor);
421 }
422
423 /* Return the list of projects for which it requires a resource delta. This builder's project
424 * is implicitly included and need not be specified. Builders must re-specify the list
425 * of interesting projects every time they are run as this is not carried forward
426 * beyond the next build. Missing projects should be specified but will be ignored until
427 * they are added to the workspace.
428 */

429 private IProject[] getRequiredProjects(boolean includeBinaryPrerequisites) {
430     if (javaProject == null || workspaceRoot == null) return new IProject[0];
431
432     ArrayList projects = new ArrayList();
433     try {
434         IClasspathEntry[] entries = javaProject.getExpandedClasspath();
435         for (int i = 0, l = entries.length; i < l; i++) {
436             IClasspathEntry entry = entries[i];
437             IPath path = entry.getPath();
438             IProject p = null;
439             switch (entry.getEntryKind()) {
440                 case IClasspathEntry.CPE_PROJECT :
441                     p = workspaceRoot.getProject(path.lastSegment()); // missing projects are considered too
442
if (((ClasspathEntry) entry).isOptional() && !JavaProject.hasJavaNature(p)) // except if entry is optional
443
p = null;
444                     break;
445                 case IClasspathEntry.CPE_LIBRARY :
446                     if (includeBinaryPrerequisites && path.segmentCount() > 1) {
447                         // some binary resources on the class path can come from projects that are not included in the project references
448
IResource resource = workspaceRoot.findMember(path.segment(0));
449                         if (resource instanceof IProject)
450                             p = (IProject) resource;
451                     }
452             }
453             if (p != null && !projects.contains(p))
454                 projects.add(p);
455         }
456     } catch(JavaModelException e) {
457         return new IProject[0];
458     }
459     IProject[] result = new IProject[projects.size()];
460     projects.toArray(result);
461     return result;
462 }
463
464 boolean hasBuildpathErrors() throws CoreException {
465     IMarker[] markers = this.currentProject.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
466     for (int i = 0, l = markers.length; i < l; i++)
467         if (markers[i].getAttribute(IJavaModelMarker.CATEGORY_ID, -1) == CategorizedProblem.CAT_BUILDPATH)
468             return true;
469     return false;
470 }
471
472 private boolean hasClasspathChanged() {
473     ClasspathMultiDirectory[] newSourceLocations = nameEnvironment.sourceLocations;
474     ClasspathMultiDirectory[] oldSourceLocations = lastState.sourceLocations;
475     int newLength = newSourceLocations.length;
476     int oldLength = oldSourceLocations.length;
477     int n, o;
478     for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
479         if (newSourceLocations[n].equals(oldSourceLocations[o])) continue; // checks source & output folders
480
try {
481             if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
482
o--;
483                 continue;
484             }
485         } catch (CoreException ignore) { // skip it
486
}
487         if (DEBUG) {
488             System.out.println("New location: " + newSourceLocations[n] + "\n!= old location: " + oldSourceLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
489
printLocations(newSourceLocations, oldSourceLocations);
490         }
491         return true;
492     }
493     while (n < newLength) {
494         try {
495             if (newSourceLocations[n].sourceFolder.members().length == 0) { // added new empty source folder
496
n++;
497                 continue;
498             }
499         } catch (CoreException ignore) { // skip it
500
}
501         if (DEBUG) {
502             System.out.println("Added non-empty source folder"); //$NON-NLS-1$
503
printLocations(newSourceLocations, oldSourceLocations);
504         }
505         return true;
506     }
507     if (o < oldLength) {
508         if (DEBUG) {
509             System.out.println("Removed source folder"); //$NON-NLS-1$
510
printLocations(newSourceLocations, oldSourceLocations);
511         }
512         return true;
513     }
514
515     ClasspathLocation[] newBinaryLocations = nameEnvironment.binaryLocations;
516     ClasspathLocation[] oldBinaryLocations = lastState.binaryLocations;
517     newLength = newBinaryLocations.length;
518     oldLength = oldBinaryLocations.length;
519     for (n = o = 0; n < newLength && o < oldLength; n++, o++) {
520         if (newBinaryLocations[n].equals(oldBinaryLocations[o])) continue;
521         if (DEBUG) {
522             System.out.println("New location: " + newBinaryLocations[n] + "\n!= old location: " + oldBinaryLocations[o]); //$NON-NLS-1$ //$NON-NLS-2$
523
printLocations(newBinaryLocations, oldBinaryLocations);
524         }
525         return true;
526     }
527     if (n < newLength || o < oldLength) {
528         if (DEBUG) {
529             System.out.println("Number of binary folders/jar files has changed:"); //$NON-NLS-1$
530
printLocations(newBinaryLocations, oldBinaryLocations);
531         }
532         return true;
533     }
534     return false;
535 }
536
537 private boolean hasJavaBuilder(IProject project) throws CoreException {
538     ICommand[] buildCommands = project.getDescription().getBuildSpec();
539     for (int i = 0, l = buildCommands.length; i < l; i++)
540         if (buildCommands[i].getBuilderName().equals(JavaCore.BUILDER_ID))
541             return true;
542     return false;
543 }
544
545 private boolean hasStructuralDelta() {
546     // handle case when currentProject has only .class file folders and/or jar files... no source/output folders
547
IResourceDelta delta = getDelta(currentProject);
548     if (delta != null && delta.getKind() != IResourceDelta.NO_CHANGE) {
549         ClasspathLocation[] classFoldersAndJars = (ClasspathLocation[]) binaryLocationsPerProject.get(currentProject);
550         if (classFoldersAndJars != null) {
551             for (int i = 0, l = classFoldersAndJars.length; i < l; i++) {
552                 ClasspathLocation classFolderOrJar = classFoldersAndJars[i]; // either a .class file folder or a zip/jar file
553
if (classFolderOrJar != null) {
554                     IPath p = classFolderOrJar.getProjectRelativePath();
555                     if (p != null) {
556                         IResourceDelta binaryDelta = delta.findMember(p);
557                         if (binaryDelta != null && binaryDelta.getKind() != IResourceDelta.NO_CHANGE)
558                             return true;
559                     }
560                 }
561             }
562         }
563     }
564     return false;
565 }
566
567 private int initializeBuilder(int kind, boolean forBuild) throws CoreException {
568     // some calls just need the nameEnvironment initialized so skip the rest
569
this.javaProject = (JavaProject) JavaCore.create(currentProject);
570     this.workspaceRoot = currentProject.getWorkspace().getRoot();
571
572     if (forBuild) {
573         // cache the known participants for this project
574
this.participants = JavaModelManager.getJavaModelManager().compilationParticipants.getCompilationParticipants(this.javaProject);
575         if (this.participants != null)
576             for (int i = 0, l = this.participants.length; i < l; i++)
577                 if (this.participants[i].aboutToBuild(this.javaProject) == CompilationParticipant.NEEDS_FULL_BUILD)
578                     kind = FULL_BUILD;
579
580         // Flush the existing external files cache if this is the beginning of a build cycle
581
String JavaDoc projectName = currentProject.getName();
582         if (builtProjects == null || builtProjects.contains(projectName)) {
583             JavaModel.flushExternalFileCache();
584             builtProjects = new ArrayList();
585         }
586         builtProjects.add(projectName);
587     }
588
589     this.binaryLocationsPerProject = new SimpleLookupTable(3);
590     this.nameEnvironment = new NameEnvironment(workspaceRoot, javaProject, binaryLocationsPerProject, notifier);
591
592     if (forBuild) {
593         String JavaDoc filterSequence = javaProject.getOption(JavaCore.CORE_JAVA_BUILD_RESOURCE_COPY_FILTER, true);
594         char[][] filters = filterSequence != null && filterSequence.length() > 0
595             ? CharOperation.splitAndTrimOn(',', filterSequence.toCharArray())
596             : null;
597         if (filters == null) {
598             this.extraResourceFileFilters = null;
599             this.extraResourceFolderFilters = null;
600         } else {
601             int fileCount = 0, folderCount = 0;
602             for (int i = 0, l = filters.length; i < l; i++) {
603                 char[] f = filters[i];
604                 if (f.length == 0) continue;
605                 if (f[f.length - 1] == '/') folderCount++; else fileCount++;
606             }
607             this.extraResourceFileFilters = new char[fileCount][];
608             this.extraResourceFolderFilters = new String JavaDoc[folderCount];
609             for (int i = 0, l = filters.length; i < l; i++) {
610                 char[] f = filters[i];
611                 if (f.length == 0) continue;
612                 if (f[f.length - 1] == '/')
613                     extraResourceFolderFilters[--folderCount] = new String JavaDoc(f, 0, f.length - 1);
614                 else
615                     extraResourceFileFilters[--fileCount] = f;
616             }
617         }
618     }
619     return kind;
620 }
621
622 private boolean isClasspathBroken(IClasspathEntry[] classpath, IProject p) throws CoreException {
623     IMarker[] markers = p.findMarkers(IJavaModelMarker.BUILDPATH_PROBLEM_MARKER, false, IResource.DEPTH_ZERO);
624     for (int i = 0, l = markers.length; i < l; i++)
625         if (markers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR)
626             return true;
627     return false;
628 }
629
630 private boolean isWorthBuilding() throws CoreException {
631     boolean abortBuilds =
632         JavaCore.ABORT.equals(javaProject.getOption(JavaCore.CORE_JAVA_BUILD_INVALID_CLASSPATH, true));
633     if (!abortBuilds) return true;
634
635     // Abort build only if there are classpath errors
636
if (isClasspathBroken(javaProject.getRawClasspath(), currentProject)) {
637         if (DEBUG)
638             System.out.println("Aborted build because project has classpath errors (incomplete or involved in cycle)"); //$NON-NLS-1$
639

640         removeProblemsAndTasksFor(currentProject); // remove all compilation problems
641

642         IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
643         marker.setAttributes(
644             new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
645             new Object JavaDoc[] {
646                 Messages.build_abortDueToClasspathProblems,
647                 new Integer JavaDoc(IMarker.SEVERITY_ERROR),
648                 new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
649                 JavaBuilder.SOURCE_ID
650             }
651         );
652         return false;
653     }
654
655     if (JavaCore.WARNING.equals(javaProject.getOption(JavaCore.CORE_INCOMPLETE_CLASSPATH, true)))
656         return true;
657
658     // make sure all prereq projects have valid build states... only when aborting builds since projects in cycles do not have build states
659
// except for projects involved in a 'warning' cycle (see below)
660
IProject[] requiredProjects = getRequiredProjects(false);
661     for (int i = 0, l = requiredProjects.length; i < l; i++) {
662         IProject p = requiredProjects[i];
663         if (getLastState(p) == null) {
664             // The prereq project has no build state: if this prereq project has a 'warning' cycle marker then allow build (see bug id 23357)
665
JavaProject prereq = (JavaProject) JavaCore.create(p);
666             if (prereq.hasCycleMarker() && JavaCore.WARNING.equals(javaProject.getOption(JavaCore.CORE_CIRCULAR_CLASSPATH, true))) {
667                 if (DEBUG)
668                     System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
669
+ " was not built since its part of a cycle"); //$NON-NLS-1$
670
continue;
671             }
672             if (!hasJavaBuilder(p)) {
673                 if (DEBUG)
674                     System.out.println("Continued to build even though prereq project " + p.getName() //$NON-NLS-1$
675
+ " is not built by JavaBuilder"); //$NON-NLS-1$
676
continue;
677             }
678             if (DEBUG)
679                 System.out.println("Aborted build because prereq project " + p.getName() //$NON-NLS-1$
680
+ " was not built"); //$NON-NLS-1$
681

682             removeProblemsAndTasksFor(currentProject); // make this the only problem for this project
683
IMarker marker = currentProject.createMarker(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER);
684             marker.setAttributes(
685                 new String JavaDoc[] {IMarker.MESSAGE, IMarker.SEVERITY, IJavaModelMarker.CATEGORY_ID, IMarker.SOURCE_ID},
686                 new Object JavaDoc[] {
687                     isClasspathBroken(prereq.getRawClasspath(), p)
688                         ? Messages.bind(Messages.build_prereqProjectHasClasspathProblems, p.getName())
689                         : Messages.bind(Messages.build_prereqProjectMustBeRebuilt, p.getName()),
690                     new Integer JavaDoc(IMarker.SEVERITY_ERROR),
691                     new Integer JavaDoc(CategorizedProblem.CAT_BUILDPATH),
692                     JavaBuilder.SOURCE_ID
693                 }
694             );
695             return false;
696         }
697     }
698     return true;
699 }
700
701 /*
702  * Instruct the build manager that this project is involved in a cycle and
703  * needs to propagate structural changes to the other projects in the cycle.
704  */

705 void mustPropagateStructuralChanges() {
706     HashSet cycleParticipants = new HashSet(3);
707     javaProject.updateCycleParticipants(new ArrayList(), cycleParticipants, workspaceRoot, new HashSet(3), null);
708     IPath currentPath = javaProject.getPath();
709     Iterator i= cycleParticipants.iterator();
710     while (i.hasNext()) {
711         IPath participantPath = (IPath) i.next();
712         if (participantPath != currentPath) {
713             IProject project = workspaceRoot.getProject(participantPath.segment(0));
714             if (hasBeenBuilt(project)) {
715                 if (DEBUG)
716                     System.out.println("Requesting another build iteration since cycle participant " + project.getName() //$NON-NLS-1$
717
+ " has not yet seen some structural changes"); //$NON-NLS-1$
718
needRebuild();
719                 return;
720             }
721         }
722     }
723 }
724
725 private void printLocations(ClasspathLocation[] newLocations, ClasspathLocation[] oldLocations) {
726     System.out.println("New locations:"); //$NON-NLS-1$
727
for (int i = 0, length = newLocations.length; i < length; i++)
728         System.out.println(" " + newLocations[i].debugPathString()); //$NON-NLS-1$
729
System.out.println("Old locations:"); //$NON-NLS-1$
730
for (int i = 0, length = oldLocations.length; i < length; i++)
731         System.out.println(" " + oldLocations[i].debugPathString()); //$NON-NLS-1$
732
}
733
734 private void recordNewState(State state) {
735     Object JavaDoc[] keyTable = binaryLocationsPerProject.keyTable;
736     for (int i = 0, l = keyTable.length; i < l; i++) {
737         IProject prereqProject = (IProject) keyTable[i];
738         if (prereqProject != null && prereqProject != currentProject)
739             state.recordStructuralDependency(prereqProject, getLastState(prereqProject));
740     }
741
742     if (DEBUG)
743         System.out.println("Recording new state : " + state); //$NON-NLS-1$
744
// state.dump();
745
JavaModelManager.getJavaModelManager().setLastBuiltState(currentProject, state);
746 }
747
748 /**
749  * String representation for debugging purposes
750  */

751 public String JavaDoc toString() {
752     return currentProject == null
753         ? "JavaBuilder for unknown project" //$NON-NLS-1$
754
: "JavaBuilder for " + currentProject.getName(); //$NON-NLS-1$
755
}
756 }
757
Popular Tags