new compiler api: persistent state splitted to source and output state
[idea/community.git] / java / compiler / impl / src / com / intellij / compiler / impl / CompilerCacheManager.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 package com.intellij.compiler.impl;
17
18 import com.intellij.compiler.impl.newApi.NewCompiler;
19 import com.intellij.compiler.impl.newApi.NewCompilerCache;
20 import com.intellij.openapi.Disposable;
21 import com.intellij.openapi.compiler.*;
22 import com.intellij.openapi.compiler.Compiler;
23 import com.intellij.openapi.components.ProjectComponent;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.util.ShutDownTracker;
27 import com.intellij.openapi.util.io.FileUtil;
28 import org.jetbrains.annotations.NonNls;
29 import org.jetbrains.annotations.NotNull;
30
31 import java.io.DataInput;
32 import java.io.DataOutput;
33 import java.io.File;
34 import java.io.IOException;
35 import java.util.ArrayList;
36 import java.util.HashMap;
37 import java.util.List;
38 import java.util.Map;
39
40 /**
41  * @author Eugene Zhuravlev
42  *         Date: May 4, 2008
43  */
44 public class CompilerCacheManager implements ProjectComponent {
45   private static final Logger LOG = Logger.getInstance("#com.intellij.compiler.impl.CompilerCacheManager");
46   private final Map<Compiler, Object> myCompilerToCacheMap = new HashMap<Compiler, Object>();
47   private final Map<NewCompiler<?,?,?>, NewCompilerCache<?,?,?>> myNewCachesMap = new HashMap<NewCompiler<?,?,?>, NewCompilerCache<?,?,?>>();
48   private final List<Disposable> myCacheDisposables = new ArrayList<Disposable>();
49   private final File myCachesRoot;
50   private final Runnable myShutdownTask = new Runnable() {
51     public void run() {
52       flushCaches();
53     }
54   };
55   private final Project myProject;
56
57   public CompilerCacheManager(Project project) {
58     myProject = project;
59     myCachesRoot = CompilerPaths.getCacheStoreDirectory(project);
60   }
61
62   public static CompilerCacheManager getInstance(Project project) {
63     return project.getComponent(CompilerCacheManager.class);
64   }
65   
66   public void projectOpened() {
67     ShutDownTracker.getInstance().registerShutdownTask(myShutdownTask);
68   }
69
70   public void projectClosed() {
71     ShutDownTracker.getInstance().unregisterShutdownTask(myShutdownTask);
72     flushCaches();
73   }
74
75   @NotNull
76   public String getComponentName() {
77     return "CompilerCacheManager";
78   }
79
80   public void initComponent() {
81   }
82
83   public void disposeComponent() {
84     flushCaches();
85   }
86   
87   private File getCompilerRootDir(final Compiler compiler) {
88     final File dir = new File(myCachesRoot, getCompilerIdString(compiler));
89     dir.mkdirs();
90     return dir;
91   }
92
93   public synchronized <Key, SourceState, OutputState> NewCompilerCache<Key, SourceState, OutputState>
94                              getNewCompilerCache(NewCompiler<Key, SourceState, OutputState> compiler) throws IOException {
95     NewCompilerCache<?,?,?> cache = myNewCachesMap.get(compiler);
96     if (cache == null) {
97       final NewCompilerCache<?,?,?> newCache = new NewCompilerCache<Key, SourceState, OutputState>(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler));
98       myNewCachesMap.put(compiler, newCache);
99       myCacheDisposables.add(new Disposable() {
100         @Override
101         public void dispose() {
102           newCache.close();
103         }
104       });
105       cache = newCache;
106     }
107     //noinspection unchecked
108     return (NewCompilerCache<Key, SourceState, OutputState>)cache;
109   }
110
111   public synchronized FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException {
112     Object cache = myCompilerToCacheMap.get(compiler);
113     if (cache == null) {
114       final FileProcessingCompilerStateCache stateCache = new FileProcessingCompilerStateCache(getCompilerRootDir(compiler),
115           compiler
116       );
117       myCompilerToCacheMap.put(compiler, stateCache);
118       myCacheDisposables.add(new Disposable() {
119         public void dispose() {
120           stateCache.close();
121         }
122       });
123       cache = stateCache;
124     }
125     else {
126       LOG.assertTrue(cache instanceof FileProcessingCompilerStateCache);
127     }
128     return (FileProcessingCompilerStateCache)cache;
129   }
130
131   public synchronized StateCache<ValidityState> getGeneratingCompilerCache(final GeneratingCompiler compiler) throws IOException {
132     Object cache = myCompilerToCacheMap.get(compiler);
133     if (cache == null) {
134       final File cacheDir = getCompilerRootDir(compiler);
135       final StateCache<ValidityState> stateCache = new StateCache<ValidityState>(new File(cacheDir, "timestamps")) {
136         public ValidityState read(DataInput stream) throws IOException {
137           return compiler.createValidityState(stream);
138         }
139   
140         public void write(ValidityState validityState, DataOutput out) throws IOException {
141           validityState.save(out);
142         }
143       };
144       myCompilerToCacheMap.put(compiler, stateCache);
145       myCacheDisposables.add(new Disposable() {
146         public void dispose() {
147           try {
148             stateCache.close();
149           }
150           catch (IOException e) {
151             LOG.info(e);
152           }
153         }
154       });
155       cache = stateCache;
156     }
157     return (StateCache<ValidityState>)cache;
158   }
159
160   public static String getCompilerIdString(Compiler compiler) {
161     @NonNls String description = compiler.getDescription();
162     return description.replaceAll("\\s+", "_").replaceAll("[\\.\\?]", "_").toLowerCase();
163   }
164   
165   public synchronized void flushCaches() {
166     for (Disposable disposable : myCacheDisposables) {
167       try {
168         disposable.dispose();
169       }
170       catch (Throwable e) {
171         LOG.info(e);
172       }
173     }
174     myCacheDisposables.clear();
175     myNewCachesMap.clear();
176     myCompilerToCacheMap.clear();
177   }
178
179   public void clearCaches(final CompileContext context) {
180     flushCaches();
181     final File[] children = myCachesRoot.listFiles();
182     if (children != null) {
183       for (final File child : children) {
184         final boolean deleteOk = FileUtil.delete(child);
185         if (!deleteOk) {
186           context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.failed.to.delete", child.getPath()), null, -1, -1);
187         }
188       }
189     }
190   }
191 }