001 /* 002 * Copyright 2010-2014 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.lang.resolve.kotlin; 018 019 import com.intellij.ide.highlighter.JavaClassFileType; 020 import com.intellij.openapi.Disposable; 021 import com.intellij.openapi.application.ApplicationManager; 022 import com.intellij.openapi.components.ServiceManager; 023 import com.intellij.openapi.vfs.VirtualFile; 024 import org.jetbrains.annotations.NotNull; 025 import org.jetbrains.annotations.Nullable; 026 027 public final class KotlinBinaryClassCache implements Disposable { 028 private static class RequestCache { 029 VirtualFile virtualFile; 030 long modificationStamp; 031 VirtualFileKotlinClass virtualFileKotlinClass; 032 033 public VirtualFileKotlinClass cache(VirtualFile file, VirtualFileKotlinClass aClass) { 034 virtualFile = file; 035 virtualFileKotlinClass = aClass; 036 modificationStamp = file.getModificationStamp(); 037 038 return aClass; 039 } 040 } 041 042 private final ThreadLocal<RequestCache> cache = 043 new ThreadLocal<RequestCache>() { 044 @Override 045 protected RequestCache initialValue() { 046 return new RequestCache(); 047 } 048 }; 049 050 @Nullable 051 public static KotlinJvmBinaryClass getKotlinBinaryClass(@NotNull VirtualFile file) { 052 if (file.getFileType() != JavaClassFileType.INSTANCE) return null; 053 054 KotlinBinaryClassCache service = ServiceManager.getService(KotlinBinaryClassCache.class); 055 RequestCache requestCache = service.cache.get(); 056 057 if (file.getModificationStamp() == requestCache.modificationStamp && file.equals(requestCache.virtualFile)) { 058 return requestCache.virtualFileKotlinClass; 059 } 060 else { 061 ApplicationManager.getApplication().assertReadAccessAllowed(); 062 063 //noinspection deprecation 064 VirtualFileKotlinClass aClass = VirtualFileKotlinClass.OBJECT$.create(file); 065 return requestCache.cache(file, aClass); 066 } 067 } 068 069 @Override 070 public void dispose() { 071 // This is only relevant for tests. We create a new instance of Application for each test, and so a new instance of this service is 072 // also created for each test. However all tests share the same event dispatch thread, which would collect all instances of this 073 // thread-local if they're not removed properly. Each instance would transitively retain VFS resulting in OutOfMemoryError 074 cache.remove(); 075 } 076 }