/* * Copyright 2003-2015 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.nodeEditor; import jetbrains.mps.logging.Logger; import jetbrains.mps.openapi.editor.descriptor.EditorAspectDescriptor; import jetbrains.mps.smodel.language.LanguageRegistry; import jetbrains.mps.smodel.language.LanguageRegistryListener; import jetbrains.mps.smodel.language.LanguageRuntime; import org.apache.log4j.LogManager; import org.jetbrains.annotations.NotNull; import java.util.HashSet; import java.util.Set; /** * TODO: Introduce ILanguageAspect.dispose() method * TODO: remove this class, replace with proper implementation of EditorAspectDescriptor.dispose() method * TODO: see {@link jetbrains.mps.editor.runtime.style.StyleAttributes}, that class contains similar code * * @author simon */ public class ValidEditorDescriptorsCache { private static final Logger LOG = Logger.wrap(LogManager.getLogger(ValidEditorDescriptorsCache.class)); private static ValidEditorDescriptorsCache ourInstance; private Set<EditorAspectDescriptor> myCachedEditorDescriptors = new HashSet<EditorAspectDescriptor>(); private LanguageRegistryListener myListener; public static ValidEditorDescriptorsCache getInstance() { if (ourInstance == null) { ourInstance = new ValidEditorDescriptorsCache(); } return ourInstance; } public synchronized boolean isDescriptorValid(EditorAspectDescriptor descriptor) { return myCachedEditorDescriptors.contains(descriptor); } public synchronized void markDescriptorValid(@NotNull EditorAspectDescriptor descriptor) { myCachedEditorDescriptors.add(descriptor); attachLanguageRegistryListener(); } private void cleanCaches(Iterable<LanguageRuntime> languages) { Set<EditorAspectDescriptor> descriptorsToRemove = new HashSet<EditorAspectDescriptor>(); for (LanguageRuntime language : languages) { loadEditorDescriptor(language, descriptorsToRemove); for (LanguageRuntime extendedLanguage : language.getExtendedLanguages()) { loadEditorDescriptor(extendedLanguage, descriptorsToRemove); } } synchronized (this) { myCachedEditorDescriptors.removeAll(descriptorsToRemove); if (myCachedEditorDescriptors.isEmpty()) { detachLanguageRegistryListener(); } } } private void loadEditorDescriptor(LanguageRuntime language, Set<EditorAspectDescriptor> editorDescriptors) { EditorAspectDescriptor descriptor = null; try { descriptor = language.getAspect(EditorAspectDescriptor.class); } catch (NoClassDefFoundError error) { LOG.error("Failed to get editor aspect descriptor for language: " + language, error); } if (descriptor != null) { editorDescriptors.add(descriptor); } } private void attachLanguageRegistryListener() { if (myListener == null) { LanguageRegistry.getInstance().addRegistryListener(myListener = new InvalidateCacheListener()); } } private void detachLanguageRegistryListener() { if (myListener != null) { LanguageRegistry.getInstance().removeRegistryListener(myListener); myListener = null; } } private class InvalidateCacheListener implements LanguageRegistryListener { @Override public void afterLanguagesLoaded(Iterable<LanguageRuntime> languages) { cleanCaches(languages); } @Override public void beforeLanguagesUnloaded(Iterable<LanguageRuntime> languages) { cleanCaches(languages); } } }