2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com
.intellij
.compiler
;
18 import com
.intellij
.compiler
.impl
.*;
19 import com
.intellij
.compiler
.impl
.javaCompiler
.AnnotationProcessingCompiler
;
20 import com
.intellij
.compiler
.impl
.javaCompiler
.JavaCompiler
;
21 import com
.intellij
.compiler
.impl
.resourceCompiler
.ResourceCompiler
;
22 import com
.intellij
.compiler
.impl
.rmiCompiler
.RmicCompiler
;
23 import com
.intellij
.openapi
.compiler
.*;
24 import com
.intellij
.openapi
.compiler
.Compiler
;
25 import com
.intellij
.openapi
.extensions
.Extensions
;
26 import com
.intellij
.openapi
.fileTypes
.FileType
;
27 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
28 import com
.intellij
.openapi
.module
.Module
;
29 import com
.intellij
.openapi
.project
.Project
;
30 import com
.intellij
.openapi
.vfs
.LocalFileSystem
;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.packaging
.impl
.compiler
.IncrementalArtifactsCompiler
;
33 import com
.intellij
.util
.ArrayUtil
;
34 import com
.intellij
.util
.Chunk
;
35 import com
.intellij
.util
.containers
.ContainerUtil
;
36 import com
.intellij
.util
.graph
.CachingSemiGraph
;
37 import com
.intellij
.util
.graph
.Graph
;
38 import com
.intellij
.util
.graph
.GraphGenerator
;
39 import com
.intellij
.util
.messages
.MessageBus
;
40 import com
.intellij
.util
.messages
.MessageBusConnection
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
44 import java
.lang
.reflect
.Array
;
46 import java
.util
.concurrent
.Semaphore
;
48 public class CompilerManagerImpl
extends CompilerManager
{
49 private final Project myProject
;
51 private final List
<Compiler
> myCompilers
= new ArrayList
<Compiler
>();
52 private final List
<TranslatingCompiler
> myTranslators
= new ArrayList
<TranslatingCompiler
>();
54 private final List
<CompileTask
> myBeforeTasks
= new ArrayList
<CompileTask
>();
55 private final List
<CompileTask
> myAfterTasks
= new ArrayList
<CompileTask
>();
56 private final Set
<FileType
> myCompilableTypes
= new HashSet
<FileType
>();
57 private final CompilationStatusListener myEventPublisher
;
58 private final Semaphore myCompilationSemaphore
= new Semaphore(1, true);
59 private final Map
<Compiler
, Set
<FileType
>> myCompilerToInputTypes
= new HashMap
<Compiler
, Set
<FileType
>>();
60 private final Map
<Compiler
, Set
<FileType
>> myCompilerToOutputTypes
= new HashMap
<Compiler
, Set
<FileType
>>();
62 public CompilerManagerImpl(final Project project
, CompilerConfigurationImpl compilerConfiguration
, MessageBus messageBus
) {
64 myEventPublisher
= messageBus
.syncPublisher(CompilerTopics
.COMPILATION_STATUS
);
66 // predefined compilers
67 addTranslatingCompiler(new AnnotationProcessingCompiler(project
), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.JAVA
)), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.JAVA
, StdFileTypes
.CLASS
)));
68 addTranslatingCompiler(new JavaCompiler(project
), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.JAVA
)), new HashSet
<FileType
>(Arrays
.asList(StdFileTypes
.CLASS
)));
69 addCompiler(new ResourceCompiler(project
, compilerConfiguration
));
70 addCompiler(new RmicCompiler());
71 addCompiler(new IncrementalArtifactsCompiler());
73 for(Compiler compiler
: Extensions
.getExtensions(Compiler
.EP_NAME
, myProject
)) {
74 addCompiler(compiler
);
76 for(CompilerFactory factory
: Extensions
.getExtensions(CompilerFactory
.EP_NAME
, myProject
)) {
77 Compiler
[] compilers
= factory
.createCompilers(this);
78 for (Compiler compiler
: compilers
) {
79 addCompiler(compiler
);
83 addCompilableFileType(StdFileTypes
.JAVA
);
85 //addCompiler(new DummyTransformingCompiler()); // this one is for testing purposes only
86 //addCompiler(new DummySourceGeneratingCompiler(myProject)); // this one is for testing purposes only
89 ApplicationManager.getApplication().invokeLater(new Runnable() {
91 ApplicationManager.getApplication().runWriteAction(new Runnable() {
93 FileTypeManager.getInstance().registerFileType(DummyTranslatingCompiler.INPUT_FILE_TYPE, DummyTranslatingCompiler.FILETYPE_EXTENSION);
94 addTranslatingCompiler(
95 new DummyTranslatingCompiler(),
96 new HashSet<FileType>(Arrays.asList(DummyTranslatingCompiler.INPUT_FILE_TYPE)),
97 new HashSet<FileType>(Arrays.asList( StdFileTypes.JAVA))
107 public Semaphore
getCompilationSemaphore() {
108 return myCompilationSemaphore
;
111 public boolean isCompilationActive() {
112 return myCompilationSemaphore
.availablePermits() == 0;
115 public void addTranslatingCompiler(@NotNull final TranslatingCompiler compiler
, final Set
<FileType
> inputTypes
, final Set
<FileType
> outputTypes
) {
116 myTranslators
.add(compiler
);
117 myCompilerToInputTypes
.put(compiler
, inputTypes
);
118 myCompilerToOutputTypes
.put(compiler
, outputTypes
);
120 final List
<Chunk
<Compiler
>> chunks
= ModuleCompilerUtil
.getSortedChunks(createCompilerGraph((List
<Compiler
>)(List
)myTranslators
));
122 myTranslators
.clear();
123 for (Chunk
<Compiler
> chunk
: chunks
) {
124 for (Compiler chunkCompiler
: chunk
.getNodes()) {
125 myTranslators
.add((TranslatingCompiler
)chunkCompiler
);
131 public Set
<FileType
> getRegisteredInputTypes(@NotNull final TranslatingCompiler compiler
) {
132 final Set
<FileType
> inputs
= myCompilerToInputTypes
.get(compiler
);
133 return inputs
!= null? Collections
.unmodifiableSet(inputs
) : Collections
.<FileType
>emptySet();
137 public Set
<FileType
> getRegisteredOutputTypes(@NotNull final TranslatingCompiler compiler
) {
138 final Set
<FileType
> outs
= myCompilerToOutputTypes
.get(compiler
);
139 return outs
!= null? Collections
.unmodifiableSet(outs
) : Collections
.<FileType
>emptySet();
142 public final void addCompiler(@NotNull Compiler compiler
) {
143 if (compiler
instanceof TranslatingCompiler
) {
144 myTranslators
.add((TranslatingCompiler
)compiler
);
148 myCompilers
.add(compiler
);
152 public final void removeCompiler(@NotNull Compiler compiler
) {
153 if (compiler
instanceof TranslatingCompiler
) {
154 myTranslators
.remove(compiler
);
157 myCompilers
.remove(compiler
);
159 myCompilerToInputTypes
.remove(compiler
);
160 myCompilerToOutputTypes
.remove(compiler
);
164 public <T
extends Compiler
> T
[] getCompilers(@NotNull Class
<T
> compilerClass
) {
165 return getCompilers(compilerClass
, CompilerFilter
.ALL
);
169 public <T
extends Compiler
> T
[] getCompilers(@NotNull Class
<T
> compilerClass
, CompilerFilter filter
) {
170 final List
<T
> compilers
= new ArrayList
<T
>(myCompilers
.size());
171 for (final Compiler item
: myCompilers
) {
172 if (compilerClass
.isAssignableFrom(item
.getClass()) && filter
.acceptCompiler(item
)) {
173 compilers
.add((T
)item
);
176 for (final Compiler item
: myTranslators
) {
177 if (compilerClass
.isAssignableFrom(item
.getClass()) && filter
.acceptCompiler(item
)) {
178 compilers
.add((T
)item
);
181 final T
[] array
= (T
[])Array
.newInstance(compilerClass
, compilers
.size());
182 return compilers
.toArray(array
);
185 public void addCompilableFileType(@NotNull FileType type
) {
186 myCompilableTypes
.add(type
);
189 public void removeCompilableFileType(@NotNull FileType type
) {
190 myCompilableTypes
.remove(type
);
193 public boolean isCompilableFileType(@NotNull FileType type
) {
194 return myCompilableTypes
.contains(type
);
197 public final void addBeforeTask(@NotNull CompileTask task
) {
198 myBeforeTasks
.add(task
);
201 public final void addAfterTask(@NotNull CompileTask task
) {
202 myAfterTasks
.add(task
);
206 public CompileTask
[] getBeforeTasks() {
207 return myBeforeTasks
.toArray(new CompileTask
[myBeforeTasks
.size()]);
211 public CompileTask
[] getAfterTasks() {
212 return myAfterTasks
.toArray(new CompileTask
[myAfterTasks
.size()]);
215 public void compile(@NotNull VirtualFile
[] files
, CompileStatusNotification callback
, final boolean trackDependencies
) {
216 compile(createFilesCompileScope(files
), callback
, trackDependencies
);
219 public void compile(@NotNull Module module
, CompileStatusNotification callback
, final boolean trackDependencies
) {
220 new CompileDriver(myProject
).compile(createModuleCompileScope(module
, false), new ListenerNotificator(callback
), trackDependencies
, true);
223 public void compile(@NotNull CompileScope scope
, CompileStatusNotification callback
, final boolean trackDependencies
) {
224 new CompileDriver(myProject
).compile(scope
, new ListenerNotificator(callback
), trackDependencies
, false);
227 public void make(CompileStatusNotification callback
) {
228 new CompileDriver(myProject
).make(createProjectCompileScope(myProject
), new ListenerNotificator(callback
));
231 public void make(@NotNull Module module
, CompileStatusNotification callback
) {
232 new CompileDriver(myProject
).make(createModuleCompileScope(module
, true), new ListenerNotificator(callback
));
235 public void make(@NotNull Project project
, @NotNull Module
[] modules
, CompileStatusNotification callback
) {
236 new CompileDriver(myProject
).make(createModuleGroupCompileScope(project
, modules
, true), new ListenerNotificator(callback
));
239 public void make(@NotNull CompileScope scope
, CompileStatusNotification callback
) {
240 new CompileDriver(myProject
).make(scope
, new ListenerNotificator(callback
));
243 public void make(@NotNull CompileScope scope
, CompilerFilter filter
, @Nullable CompileStatusNotification callback
) {
244 final CompileDriver compileDriver
= new CompileDriver(myProject
);
245 compileDriver
.setCompilerFilter(filter
);
246 compileDriver
.make(scope
, new ListenerNotificator(callback
));
249 public boolean isUpToDate(@NotNull final CompileScope scope
) {
250 return new CompileDriver(myProject
).isUpToDate(scope
);
253 public void rebuild(CompileStatusNotification callback
) {
254 new CompileDriver(myProject
).rebuild(new ListenerNotificator(callback
));
257 public void executeTask(@NotNull CompileTask task
, @NotNull CompileScope scope
, String contentName
, Runnable onTaskFinished
) {
258 final CompileDriver compileDriver
= new CompileDriver(myProject
);
259 compileDriver
.executeCompileTask(task
, scope
, contentName
, onTaskFinished
);
262 private final Map
<CompilationStatusListener
, MessageBusConnection
> myListenerAdapters
= new HashMap
<CompilationStatusListener
, MessageBusConnection
>();
264 public void addCompilationStatusListener(@NotNull final CompilationStatusListener listener
) {
265 final MessageBusConnection connection
= myProject
.getMessageBus().connect();
266 myListenerAdapters
.put(listener
, connection
);
267 connection
.subscribe(CompilerTopics
.COMPILATION_STATUS
, listener
);
270 public void removeCompilationStatusListener(@NotNull final CompilationStatusListener listener
) {
271 final MessageBusConnection connection
= myListenerAdapters
.remove(listener
);
272 if (connection
!= null) {
273 connection
.disconnect();
277 // Compiler tests support
279 private static List
<String
> ourDeletedPaths
;
280 private static List
<String
> ourRecompiledPaths
;
281 private static List
<String
> ourCompiledPaths
;
283 public static void testSetup() {
284 ourDeletedPaths
= new ArrayList
<String
>();
285 ourRecompiledPaths
= new ArrayList
<String
>();
286 ourCompiledPaths
= new ArrayList
<String
>();
289 public static void addDeletedPath(String path
) {
290 ourDeletedPaths
.add(path
);
293 public static void addRecompiledPath(String path
) {
294 ourRecompiledPaths
.add(path
);
297 public static void addCompiledPath(String path
) {
298 ourCompiledPaths
.add(path
);
301 public static String
[] getPathsToDelete() {
302 return ArrayUtil
.toStringArray(ourDeletedPaths
);
305 public static String
[] getPathsToRecompile() {
306 return ArrayUtil
.toStringArray(ourRecompiledPaths
);
309 public static String
[] getPathsToCompile() {
310 return ArrayUtil
.toStringArray(ourCompiledPaths
);
313 public static void clearPathsToCompile() {
314 if (ourCompiledPaths
!= null) {
315 ourCompiledPaths
.clear();
319 public boolean isExcludedFromCompilation(@NotNull VirtualFile file
) {
320 return CompilerConfiguration
.getInstance(myProject
).isExcludedFromCompilation(file
);
323 private static final OutputToSourceMapping OUTPUT_TO_SOURCE_MAPPING
= new OutputToSourceMapping() {
324 public String
getSourcePath(final String outputPath
) {
325 final LocalFileSystem lfs
= LocalFileSystem
.getInstance();
326 final VirtualFile outputFile
= lfs
.findFileByPath(outputPath
);
328 final VirtualFile sourceFile
= outputFile
!= null ? TranslatingCompilerFilesMonitor
.getSourceFileByOutput(outputFile
) : null;
329 return sourceFile
!= null? sourceFile
.getPath() : null;
333 public OutputToSourceMapping
getJavaCompilerOutputMapping() {
334 return OUTPUT_TO_SOURCE_MAPPING
;
338 public CompileScope
createFilesCompileScope(@NotNull final VirtualFile
[] files
) {
339 CompileScope
[] scopes
= new CompileScope
[files
.length
];
340 for(int i
= 0; i
< files
.length
; i
++){
341 scopes
[i
] = new OneProjectItemCompileScope(myProject
, files
[i
]);
343 return new CompositeScope(scopes
);
347 public CompileScope
createModuleCompileScope(@NotNull final Module module
, final boolean includeDependentModules
) {
348 return new ModuleCompileScope(module
, includeDependentModules
);
352 public CompileScope
createModulesCompileScope(@NotNull final Module
[] modules
, final boolean includeDependentModules
) {
353 return new ModuleCompileScope(myProject
, modules
, includeDependentModules
);
357 public CompileScope
createModuleGroupCompileScope(@NotNull final Project project
, @NotNull final Module
[] modules
, final boolean includeDependentModules
) {
358 return new ModuleCompileScope(project
, modules
, includeDependentModules
);
362 public CompileScope
createProjectCompileScope(@NotNull final Project project
) {
363 return new ProjectCompileScope(project
);
366 private Graph
<Compiler
> createCompilerGraph(final List
<Compiler
> compilers
) {
367 return GraphGenerator
.create(CachingSemiGraph
.create(new GraphGenerator
.SemiGraph
<Compiler
>() {
368 public Collection
<Compiler
> getNodes() {
372 public Iterator
<Compiler
> getIn(Compiler compiler
) {
373 final Set
<FileType
> compilerInput
= myCompilerToInputTypes
.get(compiler
);
374 if (compilerInput
== null || compilerInput
.isEmpty()) {
375 return Collections
.<Compiler
>emptySet().iterator();
378 final Set
<Compiler
> inCompilers
= new HashSet
<Compiler
>();
380 for (Map
.Entry
<Compiler
, Set
<FileType
>> entry
: myCompilerToOutputTypes
.entrySet()) {
381 final Set
<FileType
> outputs
= entry
.getValue();
382 Compiler comp
= entry
.getKey();
383 if (outputs
!= null && ContainerUtil
.intersects(compilerInput
, outputs
)) {
384 inCompilers
.add(comp
);
387 return inCompilers
.iterator();
392 private class ListenerNotificator
implements CompileStatusNotification
{
393 private final CompileStatusNotification myDelegate
;
395 private ListenerNotificator(CompileStatusNotification delegate
) {
396 myDelegate
= delegate
;
399 public void finished(boolean aborted
, int errors
, int warnings
, final CompileContext compileContext
) {
400 myEventPublisher
.compilationFinished(aborted
, errors
, warnings
, compileContext
);
401 if (myDelegate
!= null) {
402 myDelegate
.finished(aborted
, errors
, warnings
, compileContext
);