From 4e2db922d153f7d1ee25450fbde7ab33659d3372 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 25 Jun 2012 17:30:19 +0400 Subject: [PATCH] Extracted read-only superclass from ExternalAnnotationsManagerImpl. --- .../BaseExternalAnnotationsManager.java | 211 ++++++++++++++++++ .../ExternalAnnotationsManagerImpl.java | 182 +-------------- 2 files changed, 221 insertions(+), 172 deletions(-) create mode 100644 java/java-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java diff --git a/java/java-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java b/java/java-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java new file mode 100644 index 000000000000..126d35960d53 --- /dev/null +++ b/java/java-impl/src/com/intellij/codeInsight/BaseExternalAnnotationsManager.java @@ -0,0 +1,211 @@ +/* + * Copyright 2000-2012 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 com.intellij.codeInsight; + +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.*; +import com.intellij.psi.util.PsiFormatUtil; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.psi.xml.XmlDocument; +import com.intellij.psi.xml.XmlFile; +import com.intellij.psi.xml.XmlTag; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.StringBuilderSpinAllocator; +import com.intellij.util.containers.ConcurrentWeakHashMap; +import com.intellij.util.containers.ConcurrentWeakValueHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.concurrent.ConcurrentMap; + +public abstract class BaseExternalAnnotationsManager extends ExternalAnnotationsManager { + private static final Logger LOG = Logger.getInstance("#" + BaseExternalAnnotationsManager.class.getName()); + @NotNull private static final List NULL = new ArrayList(); + @NotNull protected final ConcurrentMap> myExternalAnnotations = new ConcurrentWeakValueHashMap>(); + protected final PsiManager myPsiManager; + + public BaseExternalAnnotationsManager(final PsiManager psiManager) { + myPsiManager = psiManager; + } + + @Nullable + protected static String getExternalName(PsiModifierListOwner listOwner, boolean showParamName) { + return PsiFormatUtil.getExternalName(listOwner, showParamName, Integer.MAX_VALUE); + } + + @Nullable + protected static String getFQN(String packageName, @Nullable VirtualFile virtualFile) { + if (virtualFile == null) return null; + return StringUtil.getQualifiedName(packageName, virtualFile.getNameWithoutExtension()); + } + + @Nullable + protected static String getNormalizedExternalName(@NotNull PsiModifierListOwner owner) { + String externalName = getExternalName(owner, true); + if (externalName != null) { + if (owner instanceof PsiParameter && owner.getParent() instanceof PsiParameterList) { + final PsiMethod method = PsiTreeUtil.getParentOfType(owner, PsiMethod.class); + if (method != null) { + externalName = + externalName.substring(0, externalName.lastIndexOf(' ') + 1) + method.getParameterList().getParameterIndex((PsiParameter)owner); + } + } + final int idx = externalName.indexOf('('); + if (idx == -1) return externalName; + final StringBuilder buf = StringBuilderSpinAllocator.alloc(); + try { + final int rightIdx = externalName.indexOf(')'); + final String[] params = externalName.substring(idx + 1, rightIdx).split(","); + buf.append(externalName.substring(0, idx + 1)); + for (String param : params) { + param = param.trim(); + final int spaceIdx = param.indexOf(' '); + buf.append(spaceIdx > -1 ? param.substring(0, spaceIdx) : param).append(", "); + } + return StringUtil.trimEnd(buf.toString(), ", ") + externalName.substring(rightIdx); + } + finally { + StringBuilderSpinAllocator.dispose(buf); + } + } + return externalName; + } + + protected abstract boolean hasAnyAnnotationsRoots(); + + @Override + @Nullable + public PsiAnnotation findExternalAnnotation(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { + return collectExternalAnnotations(listOwner).get(annotationFQN); + } + + @Override + @Nullable + public PsiAnnotation[] findExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { + final Map result = collectExternalAnnotations(listOwner); + return result.isEmpty() ? null : result.values().toArray(new PsiAnnotation[result.size()]); + } + + private final Map> cache = new ConcurrentWeakHashMap>(); + @NotNull + private Map collectExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { + if (!hasAnyAnnotationsRoots()) return Collections.emptyMap(); + + Map map = cache.get(listOwner); + if (map == null) { + map = doCollect(listOwner); + cache.put(listOwner, map); + } + return map; + } + + private Map doCollect(@NotNull PsiModifierListOwner listOwner) { + final List files = findExternalAnnotationsFiles(listOwner); + if (files == null) { + return Collections.emptyMap(); + } + final Map result = new HashMap(); + for (XmlFile file : files) { + if (!file.isValid()) continue; + final XmlDocument document = file.getDocument(); + if (document == null) continue; + final XmlTag rootTag = document.getRootTag(); + if (rootTag == null) continue; + final String externalName = getExternalName(listOwner, false); + final String oldExternalName = getNormalizedExternalName(listOwner); + for (final XmlTag tag : rootTag.getSubTags()) { + final String className = tag.getAttributeValue("name"); + if (!Comparing.strEqual(className, externalName) && !Comparing.strEqual(className, oldExternalName)) { + continue; + } + for (XmlTag annotationTag : tag.getSubTags()) { + final String annotationFQN = annotationTag.getAttributeValue("name"); + final StringBuilder buf = new StringBuilder(); + for (XmlTag annotationParameter : annotationTag.getSubTags()) { + buf.append(","); + final String nameValue = annotationParameter.getAttributeValue("name"); + if (nameValue != null) { + buf.append(nameValue).append("="); + } + buf.append(StringUtil.unescapeXml(annotationParameter.getAttributeValue("val"))); + } + final String annotationText = + "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); + try { + result.put(annotationFQN, + JavaPsiFacade.getInstance(myPsiManager.getProject()).getElementFactory().createAnnotationFromText( + annotationText, null)); + } + catch (IncorrectOperationException e) { + LOG.error(e); + } + } + } + } + return result; + } + + @NotNull + protected abstract List getExternalAnnotationsRoots(@NotNull VirtualFile libraryFile); + + @Nullable + protected List findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) { + final PsiFile containingFile = listOwner.getContainingFile(); + if (!(containingFile instanceof PsiJavaFile)) { + return null; + } + final PsiJavaFile javaFile = (PsiJavaFile)containingFile; + final String packageName = javaFile.getPackageName(); + final VirtualFile virtualFile = containingFile.getVirtualFile(); + String fqn = getFQN(packageName, virtualFile); + if (fqn == null) return null; + final List files = myExternalAnnotations.get(fqn); + if (files == NULL) return null; + if (files != null) { + for (Iterator it = files.iterator(); it.hasNext();) { + if (!it.next().isValid()) it.remove(); + } + return files; + } + + if (virtualFile == null) { + return null; + } + + List possibleAnnotationsXmls = new ArrayList(); + for (VirtualFile root : getExternalAnnotationsRoots(virtualFile)) { + final VirtualFile ext = root.findFileByRelativePath(packageName.replace(".", "/") + "/" + ANNOTATIONS_XML); + if (ext == null) continue; + final PsiFile psiFile = myPsiManager.findFile(ext); + if (!(psiFile instanceof XmlFile)) continue; + possibleAnnotationsXmls.add((XmlFile)psiFile); + } + if (!possibleAnnotationsXmls.isEmpty()) { + myExternalAnnotations.put(fqn, possibleAnnotationsXmls); + return possibleAnnotationsXmls; + } + myExternalAnnotations.put(fqn, NULL); + return null; + } + + protected void dropCache() { + cache.clear(); + } +} diff --git a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java index bae6e15e502e..3ef9f9380fcc 100644 --- a/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java +++ b/java/java-impl/src/com/intellij/codeInsight/ExternalAnnotationsManagerImpl.java @@ -59,14 +59,13 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.*; import com.intellij.psi.*; import com.intellij.psi.codeStyle.CodeStyleSettingsManager; -import com.intellij.psi.util.PsiFormatUtil; -import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlDocument; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; -import com.intellij.util.*; -import com.intellij.util.containers.ConcurrentWeakHashMap; -import com.intellij.util.containers.ConcurrentWeakValueHashMap; +import com.intellij.util.ArrayUtil; +import com.intellij.util.Function; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.ThreeState; import com.intellij.util.messages.MessageBusConnection; import com.intellij.util.ui.OptionsMessageDialog; import org.jetbrains.annotations.NonNls; @@ -77,21 +76,17 @@ import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ConcurrentMap; -public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { +public class ExternalAnnotationsManagerImpl extends BaseExternalAnnotationsManager { @NotNull public static final Icon ICON = AllIcons.Modules.Annotation; private static final Logger LOG = Logger.getInstance("#" + ExternalAnnotationsManagerImpl.class.getName()); - @NotNull private final ConcurrentMap> myExternalAnnotations = new ConcurrentWeakValueHashMap>(); @NotNull private volatile ThreeState myHasAnyAnnotationsRoots = ThreeState.UNSURE; - @NotNull private static final List NULL = new ArrayList(0); - private final PsiManager myPsiManager; public ExternalAnnotationsManagerImpl(@NotNull final Project project, final PsiManager psiManager) { - myPsiManager = psiManager; + super(psiManager); final MessageBusConnection connection = project.getMessageBus().connect(project); connection.subscribe(ProjectTopics.PROJECT_ROOTS, new ModuleRootAdapter() { @Override @@ -102,7 +97,8 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { }); } - private boolean hasAnyAnnotationsRoots() { + @Override + protected boolean hasAnyAnnotationsRoots() { if (myHasAnyAnnotationsRoots == ThreeState.UNSURE) { final Module[] modules = ModuleManager.getInstance(myPsiManager.getProject()).getModules(); for (Module module : modules) { @@ -119,83 +115,6 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return myHasAnyAnnotationsRoots == ThreeState.YES; } - @Override - @Nullable - public PsiAnnotation findExternalAnnotation(@NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) { - return collectExternalAnnotations(listOwner).get(annotationFQN); - } - - @Override - @Nullable - public PsiAnnotation[] findExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { - final Map result = collectExternalAnnotations(listOwner); - return result.isEmpty() ? null : result.values().toArray(new PsiAnnotation[result.size()]); - } - - private final Map> cache = new ConcurrentWeakHashMap>(); - @NotNull - private Map collectExternalAnnotations(@NotNull final PsiModifierListOwner listOwner) { - if (!hasAnyAnnotationsRoots()) return Collections.emptyMap(); - - Map map = cache.get(listOwner); - if (map == null) { - map = doCollect(listOwner); - cache.put(listOwner, map); - } - return map; - } - - private Map doCollect(@NotNull PsiModifierListOwner listOwner) { - final List files = findExternalAnnotationsFiles(listOwner); - if (files == null) { - return Collections.emptyMap(); - } - final Map result = new HashMap(); - for (XmlFile file : files) { - if (!file.isValid()) continue; - final XmlDocument document = file.getDocument(); - if (document == null) continue; - final XmlTag rootTag = document.getRootTag(); - if (rootTag == null) continue; - final String externalName = getExternalName(listOwner, false); - final String oldExternalName = getNormalizedExternalName(listOwner); - for (final XmlTag tag : rootTag.getSubTags()) { - final String className = tag.getAttributeValue("name"); - if (!Comparing.strEqual(className, externalName) && !Comparing.strEqual(className, oldExternalName)) { - continue; - } - for (XmlTag annotationTag : tag.getSubTags()) { - final String annotationFQN = annotationTag.getAttributeValue("name"); - final StringBuilder buf = new StringBuilder(); - for (XmlTag annotationParameter : annotationTag.getSubTags()) { - buf.append(","); - final String nameValue = annotationParameter.getAttributeValue("name"); - if (nameValue != null) { - buf.append(nameValue).append("="); - } - buf.append(StringUtil.unescapeXml(annotationParameter.getAttributeValue("val"))); - } - final String annotationText = - "@" + annotationFQN + (buf.length() > 0 ? "(" + StringUtil.trimStart(buf.toString(), ",") + ")" : ""); - try { - result.put(annotationFQN, - JavaPsiFacade.getInstance(myPsiManager.getProject()).getElementFactory().createAnnotationFromText( - annotationText, null)); - } - catch (IncorrectOperationException e) { - LOG.error(e); - } - } - } - } - return result; - } - - @Nullable - private static String getExternalName(PsiModifierListOwner listOwner, boolean showParamName) { - return PsiFormatUtil.getExternalName(listOwner, showParamName, Integer.MAX_VALUE); - } - @Override public void annotateExternally(@NotNull final PsiModifierListOwner listOwner, @@ -427,10 +346,6 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { } } - private void dropCache() { - cache.clear(); - } - @Override @NotNull public AnnotationPlace chooseAnnotationsPlace(@NotNull final PsiElement element) { @@ -620,6 +535,7 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return null; } + @Override @NotNull protected List getExternalAnnotationsRoots(@NotNull VirtualFile libraryFile) { final List entries = ProjectRootManager.getInstance(myPsiManager.getProject()).getFileIndex().getOrderEntriesForFile( @@ -640,84 +556,6 @@ public class ExternalAnnotationsManagerImpl extends ExternalAnnotationsManager { return result; } - @Nullable - private List findExternalAnnotationsFiles(@NotNull PsiModifierListOwner listOwner) { - final PsiFile containingFile = listOwner.getContainingFile(); - if (!(containingFile instanceof PsiJavaFile)) { - return null; - } - final PsiJavaFile javaFile = (PsiJavaFile)containingFile; - final String packageName = javaFile.getPackageName(); - final VirtualFile virtualFile = containingFile.getVirtualFile(); - String fqn = getFQN(packageName, virtualFile); - if (fqn == null) return null; - final List files = myExternalAnnotations.get(fqn); - if (files == NULL) return null; - if (files != null) { - for (Iterator it = files.iterator(); it.hasNext();) { - if (!it.next().isValid()) it.remove(); - } - return files; - } - - if (virtualFile == null) { - return null; - } - - List possibleAnnotationsXmls = new ArrayList(); - for (VirtualFile root : getExternalAnnotationsRoots(virtualFile)) { - final VirtualFile ext = root.findFileByRelativePath(packageName.replace(".", "/") + "/" + ANNOTATIONS_XML); - if (ext == null) continue; - final PsiFile psiFile = myPsiManager.findFile(ext); - if (!(psiFile instanceof XmlFile)) continue; - possibleAnnotationsXmls.add((XmlFile)psiFile); - } - if (!possibleAnnotationsXmls.isEmpty()) { - myExternalAnnotations.put(fqn, possibleAnnotationsXmls); - return possibleAnnotationsXmls; - } - myExternalAnnotations.put(fqn, NULL); - return null; - } - - @Nullable - private static String getFQN(String packageName, @Nullable VirtualFile virtualFile) { - if (virtualFile == null) return null; - return StringUtil.getQualifiedName(packageName, virtualFile.getNameWithoutExtension()); - } - - @Nullable - private static String getNormalizedExternalName(@NotNull PsiModifierListOwner owner) { - String externalName = getExternalName(owner, true); - if (externalName != null) { - if (owner instanceof PsiParameter && owner.getParent() instanceof PsiParameterList) { - final PsiMethod method = PsiTreeUtil.getParentOfType(owner, PsiMethod.class); - if (method != null) { - externalName = - externalName.substring(0, externalName.lastIndexOf(' ') + 1) + method.getParameterList().getParameterIndex((PsiParameter)owner); - } - } - final int idx = externalName.indexOf('('); - if (idx == -1) return externalName; - final StringBuilder buf = StringBuilderSpinAllocator.alloc(); - try { - final int rightIdx = externalName.indexOf(')'); - final String[] params = externalName.substring(idx + 1, rightIdx).split(","); - buf.append(externalName.substring(0, idx + 1)); - for (String param : params) { - param = param.trim(); - final int spaceIdx = param.indexOf(' '); - buf.append(spaceIdx > -1 ? param.substring(0, spaceIdx) : param).append(", "); - } - return StringUtil.trimEnd(buf.toString(), ", ") + externalName.substring(rightIdx); - } - finally { - StringBuilderSpinAllocator.dispose(buf); - } - } - return externalName; - } - private static class MyExternalPromptDialog extends OptionsMessageDialog { private final Project myProject; private static final String ADD_IN_CODE = ProjectBundle.message("external.annotations.in.code.option");