4afce35c12ac18b133a53143ad1cb388a70b7078
[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, State> NewCompilerCache<Key, State> getNewCompilerCache(NewCompiler<Key, State> compiler) throws IOException {
94     NewCompilerCache<?, ?> cache = myNewCachesMap.get(compiler);
95     if (cache == null) {
96       final NewCompilerCache<?, ?> newCache = new NewCompilerCache<Key, State>(compiler, NewCompilerRunner.getNewCompilerCacheDir(myProject, compiler));
97       myNewCachesMap.put(compiler, newCache);
98       myCacheDisposables.add(new Disposable() {
99         @Override
100         public void dispose() {
101           newCache.close();
102         }
103       });
104       cache = newCache;
105     }
106     //noinspection unchecked
107     return (NewCompilerCache<Key, State>)cache;
108   }
109
110   public synchronized FileProcessingCompilerStateCache getFileProcessingCompilerCache(FileProcessingCompiler compiler) throws IOException {
111     Object cache = myCompilerToCacheMap.get(compiler);
112     if (cache == null) {
113       final FileProcessingCompilerStateCache stateCache = new FileProcessingCompilerStateCache(getCompilerRootDir(compiler),
114           compiler
115       );
116       myCompilerToCacheMap.put(compiler, stateCache);
117       myCacheDisposables.add(new Disposable() {
118         public void dispose() {
119           stateCache.close();
120         }
121       });
122       cache = stateCache;
123     }
124     else {
125       LOG.assertTrue(cache instanceof FileProcessingCompilerStateCache);
126     }
127     return (FileProcessingCompilerStateCache)cache;
128   }
129
130   public synchronized StateCache<ValidityState> getGeneratingCompilerCache(final GeneratingCompiler compiler) throws IOException {
131     Object cache = myCompilerToCacheMap.get(compiler);
132     if (cache == null) {
133       final File cacheDir = getCompilerRootDir(compiler);
134       final StateCache<ValidityState> stateCache = new StateCache<ValidityState>(new File(cacheDir, "timestamps")) {
135         public ValidityState read(DataInput stream) throws IOException {
136           return compiler.createValidityState(stream);
137         }
138   
139         public void write(ValidityState validityState, DataOutput out) throws IOException {
140           validityState.save(out);
141         }
142       };
143       myCompilerToCacheMap.put(compiler, stateCache);
144       myCacheDisposables.add(new Disposable() {
145         public void dispose() {
146           try {
147             stateCache.close();
148           }
149           catch (IOException e) {
150             LOG.info(e);
151           }
152         }
153       });
154       cache = stateCache;
155     }
156     return (StateCache<ValidityState>)cache;
157   }
158
159   public static String getCompilerIdString(Compiler compiler) {
160     @NonNls String description = compiler.getDescription();
161     return description.replaceAll("\\s+", "_").replaceAll("[\\.\\?]", "_").toLowerCase();
162   }
163   
164   public synchronized void flushCaches() {
165     for (Disposable disposable : myCacheDisposables) {
166       try {
167         disposable.dispose();
168       }
169       catch (Throwable e) {
170         LOG.info(e);
171       }
172     }
173     myCacheDisposables.clear();
174     myNewCachesMap.clear();
175     myCompilerToCacheMap.clear();
176   }
177
178   public void clearCaches(final CompileContext context) {
179     flushCaches();
180     final File[] children = myCachesRoot.listFiles();
181     if (children != null) {
182       for (final File child : children) {
183         final boolean deleteOk = FileUtil.delete(child);
184         if (!deleteOk) {
185           context.addMessage(CompilerMessageCategory.ERROR, CompilerBundle.message("compiler.error.failed.to.delete", child.getPath()), null, -1, -1);
186         }
187       }
188     }
189   }
190 }