From 673edf77c597da67157aaf2ff6b68ae8ce6231b5 Mon Sep 17 00:00:00 2001 From: Evgeny Pasynkov Date: Mon, 17 Jun 2013 17:29:33 +0200 Subject: [PATCH] extract ExternalResourceManagerImpl essentials to xml-psi-impl --- .../javaee/ExternalResourceManagerImpl.java | 562 +---------------- .../intellij/javaee/ResourceRegistrar.java | 0 .../intellij/javaee/StandardResourceEP.java | 0 .../javaee/StandardResourceProvider.java | 0 .../javaee/ExternalResourceManagerExImpl.java | 563 ++++++++++++++++++ .../javaee/InternalResourceProvider.java | 0 .../javaee/ResourceRegistrarImpl.java | 8 +- .../intellij/javaee/XMLCatalogManager.java | 0 .../com/intellij/xml/XmlCoreEnvironment.java | 8 +- xml/xml-psi-impl/xml-psi-impl.iml | 1 + 10 files changed, 582 insertions(+), 560 deletions(-) rename xml/{openapi => xml-psi-api}/src/com/intellij/javaee/ResourceRegistrar.java (100%) rename xml/{openapi => xml-psi-api}/src/com/intellij/javaee/StandardResourceEP.java (100%) rename xml/{openapi => xml-psi-api}/src/com/intellij/javaee/StandardResourceProvider.java (100%) create mode 100644 xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java rename xml/{impl => xml-psi-impl}/src/com/intellij/javaee/InternalResourceProvider.java (100%) rename xml/{impl => xml-psi-impl}/src/com/intellij/javaee/ResourceRegistrarImpl.java (84%) rename xml/{impl => xml-psi-impl}/src/com/intellij/javaee/XMLCatalogManager.java (100%) diff --git a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java index cd97d262957b..8606e11e899c 100644 --- a/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java +++ b/xml/impl/src/com/intellij/javaee/ExternalResourceManagerImpl.java @@ -16,570 +16,28 @@ package com.intellij.javaee; import com.intellij.application.options.PathMacrosImpl; -import com.intellij.application.options.ReplacePathToMacroMap; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.components.*; -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.extensions.Extensions; -import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.components.ServiceManager; +import com.intellij.openapi.components.State; +import com.intellij.openapi.components.Storage; +import com.intellij.openapi.components.StoragePathMacros; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.*; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiFile; -import com.intellij.psi.xml.XmlFile; -import com.intellij.util.ArrayUtil; -import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.containers.HashMap; -import com.intellij.xml.Html5SchemaProvider; -import com.intellij.xml.XmlSchemaProvider; -import com.intellij.xml.util.XmlUtil; -import org.jdom.Element; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.jetbrains.annotations.TestOnly; - -import java.io.File; -import java.net.URL; -import java.util.*; +import com.intellij.openapi.util.JDOMExternalizable; +import com.intellij.openapi.util.NotNullLazyKey; /** * @author mike */ @State(name = "ExternalResourceManagerImpl", storages = {@Storage( file = StoragePathMacros.APP_CONFIG + "/other.xml")}) -public class ExternalResourceManagerImpl extends ExternalResourceManagerEx implements JDOMExternalizable { - static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.openapi.impl.ExternalResourceManagerImpl"); - - @NonNls public static final String J2EE_1_3 = "http://java.sun.com/dtd/"; - @NonNls public static final String J2EE_1_2 = "http://java.sun.com/j2ee/dtds/"; - @NonNls public static final String J2EE_NS = "http://java.sun.com/xml/ns/j2ee/"; - @NonNls public static final String JAVAEE_NS = "http://java.sun.com/xml/ns/javaee/"; - private static final String CATALOG_PROPERTIES_ELEMENT = "CATALOG_PROPERTIES"; - - - private final Map> myResources = new HashMap>(); - private final Set myResourceLocations = new HashSet(); - - private final Set myIgnoredResources = new HashSet(); - - private final AtomicNotNullLazyValue>> myStdResources = new AtomicNotNullLazyValue>>() { - - @NotNull - @Override - protected Map> compute() { - return computeStdResources(); - } - }; - - private String myDefaultHtmlDoctype = HTML5_DOCTYPE_ELEMENT; - - private String myCatalogPropertiesFile; - private XMLCatalogManager myCatalogManager; - private static final String HTML5_DOCTYPE_ELEMENT = "HTML5"; - - protected Map> computeStdResources() { - ResourceRegistrarImpl registrar = new ResourceRegistrarImpl(); - for (StandardResourceProvider provider : Extensions.getExtensions(StandardResourceProvider.EP_NAME)) { - provider.registerResources(registrar); - } - StandardResourceEP[] extensions = Extensions.getExtensions(StandardResourceEP.EP_NAME); - for (StandardResourceEP extension : extensions) { - registrar.addStdResource(extension.url, extension.version, extension.resourcePath, null, extension.getLoaderForClass()); - } - - myIgnoredResources.addAll(registrar.getIgnored()); - return registrar.getResources(); - } - - private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); - private long myModificationCount = 0; - private final PathMacrosImpl myPathMacros; - @NonNls private static final String RESOURCE_ELEMENT = "resource"; - @NonNls private static final String URL_ATTR = "url"; - @NonNls private static final String LOCATION_ATTR = "location"; - @NonNls private static final String IGNORED_RESOURCE_ELEMENT = "ignored-resource"; - @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype"; - private static final String DEFAULT_VERSION = null; - +public class ExternalResourceManagerImpl extends ExternalResourceManagerExImpl implements JDOMExternalizable { public ExternalResourceManagerImpl(PathMacrosImpl pathMacros) { - myPathMacros = pathMacros; + super(pathMacros); } - public boolean isStandardResource(VirtualFile file) { - VirtualFile parent = file.getParent(); - return parent != null && parent.getName().equals("standardSchemas"); - } - - @Override - public boolean isUserResource(VirtualFile file) { - return myResourceLocations.contains(file.getUrl()); - } - - @Nullable - static Map getMap(@NotNull final Map> resources, - @Nullable final String version, - final boolean create) { - Map map = resources.get(version); - if (map == null) { - if (create) { - map = ContainerUtil.newHashMap(); - resources.put(version, map); - } - else if (version == null || !version.equals(DEFAULT_VERSION)) { - map = resources.get(DEFAULT_VERSION); - } - } - - return map; - } - - public String getResourceLocation(String url) { - return getResourceLocation(url, DEFAULT_VERSION); - } - - public String getResourceLocation(@NonNls String url, String version) { - String result = getUserResource(url, version); - if (result == null) { - XMLCatalogManager manager = getCatalogManager(); - if (manager != null) { - result = manager.resolve(url); - } - } - if (result == null) { - result = getStdResource(url, version); - } - if (result == null) { - result = url; - } - return result; - } - - @Override - @Nullable - public String getUserResource(Project project, String url, String version) { - String resource = getProjectResources(project).getUserResource(url, version); - return resource == null ? getUserResource(url, version) : resource; - } - - @Override - @Nullable - public String getStdResource(String url, String version) { - Map map = getMap(myStdResources.getValue(), version, false); - if (map != null) { - Resource resource = map.get(url); - return resource == null ? null : resource.getResourceUrl(); - } - else { - return null; - } - } - - @Nullable - private String getUserResource(String url, String version) { - Map map = getMap(myResources, version, false); - return map != null ? map.get(url) : null; - } - - public String getResourceLocation(@NonNls String url, @NotNull Project project) { - String location = getProjectResources(project).getResourceLocation(url); - return location == null || location.equals(url) ? getResourceLocation(url) : location; - } - - public String getResourceLocation(@NonNls String url, String version, @NotNull Project project) { - String location = getProjectResources(project).getResourceLocation(url, version); - return location == null || location.equals(url) ? getResourceLocation(url, version) : location; - } - - @Nullable - public PsiFile getResourceLocation(@NotNull @NonNls final String url, @NotNull final PsiFile baseFile, final String version) { - final XmlFile schema = XmlSchemaProvider.findSchema(url, baseFile); - if (schema != null) { - return schema; - } - final String location = getResourceLocation(url, version, baseFile.getProject()); - return XmlUtil.findXmlFile(baseFile, location); - } - - public String[] getResourceUrls(FileType fileType, final boolean includeStandard) { - return getResourceUrls(fileType, DEFAULT_VERSION, includeStandard); - } - - public String[] getResourceUrls(@Nullable final FileType fileType, @NonNls final String version, final boolean includeStandard) { - final List result = new LinkedList(); - addResourcesFromMap(result, version, myResources); - - if (includeStandard) { - addResourcesFromMap(result, version, myStdResources.getValue()); - } - - return ArrayUtil.toStringArray(result); - } - - private static void addResourcesFromMap(final List result, - String version, - Map> resourcesMap) { - Map resources = getMap(resourcesMap, version, false); - if (resources == null) return; - result.addAll(resources.keySet()); - } - - @TestOnly - public static void addTestResource(final String url, final String location, Disposable parentDisposable) { - final ExternalResourceManagerImpl instance = (ExternalResourceManagerImpl)getInstance(); - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - instance.addResource(url, location); - } - }); - Disposer.register(parentDisposable, new Disposable() { - @Override - public void dispose() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - instance.removeResource(url); - } - }); - } - }); - } - public void addResource(String url, String location) { - addResource(url, DEFAULT_VERSION, location); - } - - public void addResource(@NonNls String url, @NonNls String version, @NonNls String location) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - addSilently(url, version, location); - fireExternalResourceChanged(); - } - - private void addSilently(String url, String version, String location) { - final Map map = getMap(myResources, version, true); - assert map != null; - map.put(url, location); - myResourceLocations.add(location); - myModificationCount++; - } - - public void removeResource(String url) { - removeResource(url, DEFAULT_VERSION); - } - - public void removeResource(String url, String version) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - Map map = getMap(myResources, version, false); - if (map != null) { - String location = map.remove(url); - if (location != null) { - myResourceLocations.remove(location); - } - myModificationCount++; - fireExternalResourceChanged(); - } - } - - @Override - public void removeResource(String url, @NotNull Project project) { - getProjectResources(project).removeResource(url); - } - - @Override - public void addResource(@NonNls String url, @NonNls String location, @NotNull Project project) { - getProjectResources(project).addResource(url, location); - } - - public String[] getAvailableUrls() { - Set urls = new HashSet(); - for (Map map : myResources.values()) { - urls.addAll(map.keySet()); - } - return ArrayUtil.toStringArray(urls); - } - - @Override - public String[] getAvailableUrls(Project project) { - return getProjectResources(project).getAvailableUrls(); - } - - public void clearAllResources() { - myResources.clear(); - myIgnoredResources.clear(); - } - - public void clearAllResources(Project project) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - clearAllResources(); - getProjectResources(project).clearAllResources(); - myModificationCount++; - fireExternalResourceChanged(); - } - - public void addIgnoredResource(String url) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - addIgnoredSilently(url); - fireExternalResourceChanged(); - } - - private void addIgnoredSilently(String url) { - myIgnoredResources.add(url); - myModificationCount++; - } - - public void removeIgnoredResource(String url) { - ApplicationManager.getApplication().assertWriteAccessAllowed(); - if (myIgnoredResources.remove(url)) { - myModificationCount++; - fireExternalResourceChanged(); - } - } - - public boolean isIgnoredResource(String url) { - myStdResources.getValue(); // ensure ignored resources are loaded - return myIgnoredResources.contains(url) || isImplicitNamespaceDescriptor(url); - } - - private static boolean isImplicitNamespaceDescriptor(String url) { - for (ImplicitNamespaceDescriptorProvider namespaceDescriptorProvider : Extensions - .getExtensions(ImplicitNamespaceDescriptorProvider.EP_NAME)) { - if (namespaceDescriptorProvider.getNamespaceDescriptor(null, url, null) != null) return true; - } - return false; - } - - public String[] getIgnoredResources() { - myStdResources.getValue(); // ensure ignored resources are loaded - return ArrayUtil.toStringArray(myIgnoredResources); - } - - public long getModificationCount() { - return myModificationCount; - } - - @Override - public long getModificationCount(@NotNull Project project) { - return getProjectResources(project).getModificationCount(); - } - - public void readExternal(Element element) throws InvalidDataException { - final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); - myPathMacros.addMacroExpands(macroExpands); - macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive); - - myModificationCount++; - for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) { - Element e = (Element)o1; - addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); - } - - for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) { - Element e = (Element)o; - addIgnoredSilently(e.getAttributeValue(URL_ATTR)); - } - - Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); - if (child != null) { - String text = child.getText(); - if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) { - text = HTML5_DOCTYPE_ELEMENT; - } - myDefaultHtmlDoctype = text; - } - Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); - if (catalogElement != null) { - myCatalogPropertiesFile = catalogElement.getTextTrim(); - } - } - - public void writeExternal(Element element) throws WriteExternalException { - final String[] urls = getAvailableUrls(); - for (String url : urls) { - if (url == null) continue; - String location = getResourceLocation(url); - if (location == null) continue; - final Element e = new Element(RESOURCE_ELEMENT); - - e.setAttribute(URL_ATTR, url); - e.setAttribute(LOCATION_ATTR, location.replace(File.separatorChar, '/')); - element.addContent(e); - } - - final String[] ignoredResources = getIgnoredResources(); - for (String ignoredResource : ignoredResources) { - final Element e = new Element(IGNORED_RESOURCE_ELEMENT); - - e.setAttribute(URL_ATTR, ignoredResource); - element.addContent(e); - } - - if (myDefaultHtmlDoctype != null && !HTML5_DOCTYPE_ELEMENT.equals(myDefaultHtmlDoctype)) { - final Element e = new Element(HTML_DEFAULT_DOCTYPE_ELEMENT); - e.setText(myDefaultHtmlDoctype); - element.addContent(e); - } - if (myCatalogPropertiesFile != null) { - Element properties = new Element(CATALOG_PROPERTIES_ELEMENT); - properties.setText(myCatalogPropertiesFile); - element.addContent(properties); - } - final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap(); - PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements); - macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive); - } - - public void addExternalResourceListener(ExternalResourceListener listener) { - myListeners.add(listener); - } - - public void removeExternalResourceListener(ExternalResourceListener listener) { - myListeners.remove(listener); - } - - private void fireExternalResourceChanged() { - for (ExternalResourceListener listener : myListeners) { - listener.externalResourceChanged(); - } - } - - Collection> getStandardResources() { - return myStdResources.getValue().values(); - } - - private static final NotNullLazyKey INSTANCE_CACHE = ServiceManager.createLazyKey(ProjectResources.class); - private static ExternalResourceManagerImpl getProjectResources(Project project) { + @Override + protected ExternalResourceManagerExImpl getProjectResources(Project project) { return INSTANCE_CACHE.getValue(project); } - - @Override - @NotNull - public String getDefaultHtmlDoctype(@NotNull Project project) { - final String doctype = getProjectResources(project).myDefaultHtmlDoctype; - if (XmlUtil.XHTML_URI.equals(doctype)) { - return XmlUtil.XHTML4_SCHEMA_LOCATION; - } - else if (HTML5_DOCTYPE_ELEMENT.equals(doctype)) { - return Html5SchemaProvider.getHtml5SchemaLocation(); - } - else { - return doctype; - } - } - - @Override - public void setDefaultHtmlDoctype(@NotNull String defaultHtmlDoctype, @NotNull Project project) { - getProjectResources(project).setDefaultHtmlDoctype(defaultHtmlDoctype); - } - - @Override - public String getCatalogPropertiesFile() { - return myCatalogPropertiesFile; - } - - @Override - public void setCatalogPropertiesFile(String filePath) { - myCatalogManager = null; - myCatalogPropertiesFile = filePath; - myModificationCount++; - } - - @Nullable - private XMLCatalogManager getCatalogManager() { - if (myCatalogManager == null && myCatalogPropertiesFile != null) { - myCatalogManager = new XMLCatalogManager(myCatalogPropertiesFile); - } - return myCatalogManager; - } - - private void setDefaultHtmlDoctype(String defaultHtmlDoctype) { - myModificationCount++; - - if (Html5SchemaProvider.getHtml5SchemaLocation().equals(defaultHtmlDoctype)) { - myDefaultHtmlDoctype = HTML5_DOCTYPE_ELEMENT; - } - else { - myDefaultHtmlDoctype = defaultHtmlDoctype; - } - fireExternalResourceChanged(); - } - - @TestOnly - public static void registerResourceTemporarily(final String url, final String location, Disposable disposable) { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - getInstance().addResource(url, location); - } - }); - - Disposer.register(disposable, new Disposable() { - @Override - public void dispose() { - ApplicationManager.getApplication().runWriteAction(new Runnable() { - public void run() { - getInstance().removeResource(url); - } - }); - } - }); - } - - static class Resource { - String file; - ClassLoader classLoader; - Class clazz; - - @Nullable - String getResourceUrl() { - - if (classLoader == null && clazz == null) return file; - - final URL resource = clazz == null ? classLoader.getResource(file) : clazz.getResource(file); - classLoader = null; - clazz = null; - if (resource == null) { - String message = "Cannot find standard resource. filename:" + file + " class=" + classLoader; - if (ApplicationManager.getApplication().isUnitTestMode()) { - LOG.error(message); - } - else { - LOG.warn(message); - } - - return null; - } - - String path = FileUtil.unquote(resource.toString()); - // this is done by FileUtil for windows - path = path.replace('\\','/'); - file = path; - return path; - } - - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - Resource resource = (Resource)o; - - if (classLoader != resource.classLoader) return false; - if (clazz != resource.clazz) return false; - if (file != null ? !file.equals(resource.file) : resource.file != null) return false; - - return true; - } - - @Override - public int hashCode() { - return file.hashCode(); - } - - @Override - public String toString() { - return file + " for " + classLoader; - } - } } diff --git a/xml/openapi/src/com/intellij/javaee/ResourceRegistrar.java b/xml/xml-psi-api/src/com/intellij/javaee/ResourceRegistrar.java similarity index 100% rename from xml/openapi/src/com/intellij/javaee/ResourceRegistrar.java rename to xml/xml-psi-api/src/com/intellij/javaee/ResourceRegistrar.java diff --git a/xml/openapi/src/com/intellij/javaee/StandardResourceEP.java b/xml/xml-psi-api/src/com/intellij/javaee/StandardResourceEP.java similarity index 100% rename from xml/openapi/src/com/intellij/javaee/StandardResourceEP.java rename to xml/xml-psi-api/src/com/intellij/javaee/StandardResourceEP.java diff --git a/xml/openapi/src/com/intellij/javaee/StandardResourceProvider.java b/xml/xml-psi-api/src/com/intellij/javaee/StandardResourceProvider.java similarity index 100% rename from xml/openapi/src/com/intellij/javaee/StandardResourceProvider.java rename to xml/xml-psi-api/src/com/intellij/javaee/StandardResourceProvider.java diff --git a/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java new file mode 100644 index 000000000000..4d58a5524bfe --- /dev/null +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ExternalResourceManagerExImpl.java @@ -0,0 +1,563 @@ +package com.intellij.javaee; + +import com.intellij.application.options.PathMacrosImpl; +import com.intellij.application.options.ReplacePathToMacroMap; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.components.ExpandMacroToPathMap; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.*; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.intellij.psi.xml.XmlFile; +import com.intellij.util.ArrayUtil; +import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.containers.HashMap; +import com.intellij.xml.Html5SchemaProvider; +import com.intellij.xml.XmlSchemaProvider; +import com.intellij.xml.util.XmlUtil; +import org.jdom.Element; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; + +import java.io.File; +import java.net.URL; +import java.util.*; + +public class ExternalResourceManagerExImpl extends ExternalResourceManagerEx { + static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.openapi.impl.ExternalResourceManagerImpl"); + + @NonNls public static final String J2EE_1_3 = "http://java.sun.com/dtd/"; + @NonNls public static final String J2EE_1_2 = "http://java.sun.com/j2ee/dtds/"; + @NonNls public static final String J2EE_NS = "http://java.sun.com/xml/ns/j2ee/"; + @NonNls public static final String JAVAEE_NS = "http://java.sun.com/xml/ns/javaee/"; + private static final String CATALOG_PROPERTIES_ELEMENT = "CATALOG_PROPERTIES"; + + + private final Map> myResources = new HashMap>(); + private final Set myResourceLocations = new HashSet(); + + private final Set myIgnoredResources = new HashSet(); + + private final AtomicNotNullLazyValue>> myStdResources = new AtomicNotNullLazyValue>>() { + + @NotNull + @Override + protected Map> compute() { + return computeStdResources(); + } + }; + + private String myDefaultHtmlDoctype = HTML5_DOCTYPE_ELEMENT; + + private String myCatalogPropertiesFile; + private XMLCatalogManager myCatalogManager; + private static final String HTML5_DOCTYPE_ELEMENT = "HTML5"; + + protected Map> computeStdResources() { + ResourceRegistrarImpl registrar = new ResourceRegistrarImpl(); + for (StandardResourceProvider provider : Extensions.getExtensions(StandardResourceProvider.EP_NAME)) { + provider.registerResources(registrar); + } + StandardResourceEP[] extensions = Extensions.getExtensions(StandardResourceEP.EP_NAME); + for (StandardResourceEP extension : extensions) { + registrar.addStdResource(extension.url, extension.version, extension.resourcePath, null, extension.getLoaderForClass()); + } + + myIgnoredResources.addAll(registrar.getIgnored()); + return registrar.getResources(); + } + + private final List myListeners = ContainerUtil.createLockFreeCopyOnWriteList(); + private long myModificationCount = 0; + private final PathMacrosImpl myPathMacros; + @NonNls private static final String RESOURCE_ELEMENT = "resource"; + @NonNls private static final String URL_ATTR = "url"; + @NonNls private static final String LOCATION_ATTR = "location"; + @NonNls private static final String IGNORED_RESOURCE_ELEMENT = "ignored-resource"; + @NonNls private static final String HTML_DEFAULT_DOCTYPE_ELEMENT = "default-html-doctype"; + private static final String DEFAULT_VERSION = null; + + public ExternalResourceManagerExImpl(PathMacrosImpl pathMacros) { + myPathMacros = pathMacros; + } + + public boolean isStandardResource(VirtualFile file) { + VirtualFile parent = file.getParent(); + return parent != null && parent.getName().equals("standardSchemas"); + } + + @Override + public boolean isUserResource(VirtualFile file) { + return myResourceLocations.contains(file.getUrl()); + } + + @Nullable + static Map getMap(@NotNull final Map> resources, + @Nullable final String version, + final boolean create) { + Map map = resources.get(version); + if (map == null) { + if (create) { + map = ContainerUtil.newHashMap(); + resources.put(version, map); + } + else if (version == null || !version.equals(DEFAULT_VERSION)) { + map = resources.get(DEFAULT_VERSION); + } + } + + return map; + } + + public String getResourceLocation(String url) { + return getResourceLocation(url, DEFAULT_VERSION); + } + + public String getResourceLocation(@NonNls String url, String version) { + String result = getUserResource(url, version); + if (result == null) { + XMLCatalogManager manager = getCatalogManager(); + if (manager != null) { + result = manager.resolve(url); + } + } + if (result == null) { + result = getStdResource(url, version); + } + if (result == null) { + result = url; + } + return result; + } + + @Override + @Nullable + public String getUserResource(Project project, String url, String version) { + String resource = getProjectResources(project).getUserResource(url, version); + return resource == null ? getUserResource(url, version) : resource; + } + + @Override + @Nullable + public String getStdResource(String url, String version) { + Map map = getMap(myStdResources.getValue(), version, false); + if (map != null) { + Resource resource = map.get(url); + return resource == null ? null : resource.getResourceUrl(); + } + else { + return null; + } + } + + @Nullable + private String getUserResource(String url, String version) { + Map map = getMap(myResources, version, false); + return map != null ? map.get(url) : null; + } + + public String getResourceLocation(@NonNls String url, @NotNull Project project) { + String location = getProjectResources(project).getResourceLocation(url); + return location == null || location.equals(url) ? getResourceLocation(url) : location; + } + + public String getResourceLocation(@NonNls String url, String version, @NotNull Project project) { + String location = getProjectResources(project).getResourceLocation(url, version); + return location == null || location.equals(url) ? getResourceLocation(url, version) : location; + } + + @Nullable + public PsiFile getResourceLocation(@NotNull @NonNls final String url, @NotNull final PsiFile baseFile, final String version) { + final XmlFile schema = XmlSchemaProvider.findSchema(url, baseFile); + if (schema != null) { + return schema; + } + final String location = getResourceLocation(url, version, baseFile.getProject()); + return XmlUtil.findXmlFile(baseFile, location); + } + + public String[] getResourceUrls(FileType fileType, final boolean includeStandard) { + return getResourceUrls(fileType, DEFAULT_VERSION, includeStandard); + } + + public String[] getResourceUrls(@Nullable final FileType fileType, @NonNls final String version, final boolean includeStandard) { + final List result = new LinkedList(); + addResourcesFromMap(result, version, myResources); + + if (includeStandard) { + addResourcesFromMap(result, version, myStdResources.getValue()); + } + + return ArrayUtil.toStringArray(result); + } + + private static void addResourcesFromMap(final List result, + String version, + Map> resourcesMap) { + Map resources = getMap(resourcesMap, version, false); + if (resources == null) return; + result.addAll(resources.keySet()); + } + + @TestOnly + public static void addTestResource(final String url, final String location, Disposable parentDisposable) { + final ExternalResourceManagerExImpl instance = (ExternalResourceManagerExImpl)getInstance(); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + instance.addResource(url, location); + } + }); + Disposer.register(parentDisposable, new Disposable() { + @Override + public void dispose() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + instance.removeResource(url); + } + }); + } + }); + } + public void addResource(String url, String location) { + addResource(url, DEFAULT_VERSION, location); + } + + public void addResource(@NonNls String url, @NonNls String version, @NonNls String location) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + addSilently(url, version, location); + fireExternalResourceChanged(); + } + + private void addSilently(String url, String version, String location) { + final Map map = getMap(myResources, version, true); + assert map != null; + map.put(url, location); + myResourceLocations.add(location); + myModificationCount++; + } + + public void removeResource(String url) { + removeResource(url, DEFAULT_VERSION); + } + + public void removeResource(String url, String version) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + Map map = getMap(myResources, version, false); + if (map != null) { + String location = map.remove(url); + if (location != null) { + myResourceLocations.remove(location); + } + myModificationCount++; + fireExternalResourceChanged(); + } + } + + @Override + public void removeResource(String url, @NotNull Project project) { + getProjectResources(project).removeResource(url); + } + + @Override + public void addResource(@NonNls String url, @NonNls String location, @NotNull Project project) { + getProjectResources(project).addResource(url, location); + } + + public String[] getAvailableUrls() { + Set urls = new HashSet(); + for (Map map : myResources.values()) { + urls.addAll(map.keySet()); + } + return ArrayUtil.toStringArray(urls); + } + + @Override + public String[] getAvailableUrls(Project project) { + return getProjectResources(project).getAvailableUrls(); + } + + public void clearAllResources() { + myResources.clear(); + myIgnoredResources.clear(); + } + + public void clearAllResources(Project project) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + clearAllResources(); + getProjectResources(project).clearAllResources(); + myModificationCount++; + fireExternalResourceChanged(); + } + + public void addIgnoredResource(String url) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + addIgnoredSilently(url); + fireExternalResourceChanged(); + } + + private void addIgnoredSilently(String url) { + myIgnoredResources.add(url); + myModificationCount++; + } + + public void removeIgnoredResource(String url) { + ApplicationManager.getApplication().assertWriteAccessAllowed(); + if (myIgnoredResources.remove(url)) { + myModificationCount++; + fireExternalResourceChanged(); + } + } + + public boolean isIgnoredResource(String url) { + myStdResources.getValue(); // ensure ignored resources are loaded + return myIgnoredResources.contains(url) || isImplicitNamespaceDescriptor(url); + } + + private static boolean isImplicitNamespaceDescriptor(String url) { + for (ImplicitNamespaceDescriptorProvider namespaceDescriptorProvider : Extensions + .getExtensions(ImplicitNamespaceDescriptorProvider.EP_NAME)) { + if (namespaceDescriptorProvider.getNamespaceDescriptor(null, url, null) != null) return true; + } + return false; + } + + public String[] getIgnoredResources() { + myStdResources.getValue(); // ensure ignored resources are loaded + return ArrayUtil.toStringArray(myIgnoredResources); + } + + public long getModificationCount() { + return myModificationCount; + } + + @Override + public long getModificationCount(@NotNull Project project) { + return getProjectResources(project).getModificationCount(); + } + + public void readExternal(Element element) throws InvalidDataException { + final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap(); + myPathMacros.addMacroExpands(macroExpands); + macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive); + + myModificationCount++; + for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) { + Element e = (Element)o1; + addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar)); + } + + for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) { + Element e = (Element)o; + addIgnoredSilently(e.getAttributeValue(URL_ATTR)); + } + + Element child = element.getChild(HTML_DEFAULT_DOCTYPE_ELEMENT); + if (child != null) { + String text = child.getText(); + if (FileUtil.toSystemIndependentName(text).endsWith(".jar!/resources/html5-schema/html5.rnc")) { + text = HTML5_DOCTYPE_ELEMENT; + } + myDefaultHtmlDoctype = text; + } + Element catalogElement = element.getChild(CATALOG_PROPERTIES_ELEMENT); + if (catalogElement != null) { + myCatalogPropertiesFile = catalogElement.getTextTrim(); + } + } + + public void writeExternal(Element element) throws WriteExternalException { + final String[] urls = getAvailableUrls(); + for (String url : urls) { + if (url == null) continue; + String location = getResourceLocation(url); + if (location == null) continue; + final Element e = new Element(RESOURCE_ELEMENT); + + e.setAttribute(URL_ATTR, url); + e.setAttribute(LOCATION_ATTR, location.replace(File.separatorChar, '/')); + element.addContent(e); + } + + final String[] ignoredResources = getIgnoredResources(); + for (String ignoredResource : ignoredResources) { + final Element e = new Element(IGNORED_RESOURCE_ELEMENT); + + e.setAttribute(URL_ATTR, ignoredResource); + element.addContent(e); + } + + if (myDefaultHtmlDoctype != null && !HTML5_DOCTYPE_ELEMENT.equals(myDefaultHtmlDoctype)) { + final Element e = new Element(HTML_DEFAULT_DOCTYPE_ELEMENT); + e.setText(myDefaultHtmlDoctype); + element.addContent(e); + } + if (myCatalogPropertiesFile != null) { + Element properties = new Element(CATALOG_PROPERTIES_ELEMENT); + properties.setText(myCatalogPropertiesFile); + element.addContent(properties); + } + final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap(); + PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements); + macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive); + } + + public void addExternalResourceListener(ExternalResourceListener listener) { + myListeners.add(listener); + } + + public void removeExternalResourceListener(ExternalResourceListener listener) { + myListeners.remove(listener); + } + + private void fireExternalResourceChanged() { + for (ExternalResourceListener listener : myListeners) { + listener.externalResourceChanged(); + } + } + + Collection> getStandardResources() { + return myStdResources.getValue().values(); + } + + + protected ExternalResourceManagerExImpl getProjectResources(Project project) { + return this; + } + + @Override + @NotNull + public String getDefaultHtmlDoctype(@NotNull Project project) { + final String doctype = getProjectResources(project).myDefaultHtmlDoctype; + if (XmlUtil.XHTML_URI.equals(doctype)) { + return XmlUtil.XHTML4_SCHEMA_LOCATION; + } + else if (HTML5_DOCTYPE_ELEMENT.equals(doctype)) { + return Html5SchemaProvider.getHtml5SchemaLocation(); + } + else { + return doctype; + } + } + + @Override + public void setDefaultHtmlDoctype(@NotNull String defaultHtmlDoctype, @NotNull Project project) { + getProjectResources(project).setDefaultHtmlDoctype(defaultHtmlDoctype); + } + + @Override + public String getCatalogPropertiesFile() { + return myCatalogPropertiesFile; + } + + @Override + public void setCatalogPropertiesFile(String filePath) { + myCatalogManager = null; + myCatalogPropertiesFile = filePath; + myModificationCount++; + } + + @Nullable + private XMLCatalogManager getCatalogManager() { + if (myCatalogManager == null && myCatalogPropertiesFile != null) { + myCatalogManager = new XMLCatalogManager(myCatalogPropertiesFile); + } + return myCatalogManager; + } + + private void setDefaultHtmlDoctype(String defaultHtmlDoctype) { + myModificationCount++; + + if (Html5SchemaProvider.getHtml5SchemaLocation().equals(defaultHtmlDoctype)) { + myDefaultHtmlDoctype = HTML5_DOCTYPE_ELEMENT; + } + else { + myDefaultHtmlDoctype = defaultHtmlDoctype; + } + fireExternalResourceChanged(); + } + + @TestOnly + public static void registerResourceTemporarily(final String url, final String location, Disposable disposable) { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + getInstance().addResource(url, location); + } + }); + + Disposer.register(disposable, new Disposable() { + @Override + public void dispose() { + ApplicationManager.getApplication().runWriteAction(new Runnable() { + public void run() { + getInstance().removeResource(url); + } + }); + } + }); + } + + static class Resource { + String file; + ClassLoader classLoader; + Class clazz; + + @Nullable + String getResourceUrl() { + + if (classLoader == null && clazz == null) return file; + + final URL resource = clazz == null ? classLoader.getResource(file) : clazz.getResource(file); + classLoader = null; + clazz = null; + if (resource == null) { + String message = "Cannot find standard resource. filename:" + file + " class=" + classLoader; + if (ApplicationManager.getApplication().isUnitTestMode()) { + LOG.error(message); + } + else { + LOG.warn(message); + } + + return null; + } + + String path = FileUtil.unquote(resource.toString()); + // this is done by FileUtil for windows + path = path.replace('\\','/'); + file = path; + return path; + } + + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Resource resource = (Resource)o; + + if (classLoader != resource.classLoader) return false; + if (clazz != resource.clazz) return false; + if (file != null ? !file.equals(resource.file) : resource.file != null) return false; + + return true; + } + + @Override + public int hashCode() { + return file.hashCode(); + } + + @Override + public String toString() { + return file + " for " + classLoader; + } + } +} diff --git a/xml/impl/src/com/intellij/javaee/InternalResourceProvider.java b/xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java similarity index 100% rename from xml/impl/src/com/intellij/javaee/InternalResourceProvider.java rename to xml/xml-psi-impl/src/com/intellij/javaee/InternalResourceProvider.java diff --git a/xml/impl/src/com/intellij/javaee/ResourceRegistrarImpl.java b/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java similarity index 84% rename from xml/impl/src/com/intellij/javaee/ResourceRegistrarImpl.java rename to xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java index 10bb8528135f..b3dcdcf7f8cd 100644 --- a/xml/impl/src/com/intellij/javaee/ResourceRegistrarImpl.java +++ b/xml/xml-psi-impl/src/com/intellij/javaee/ResourceRegistrarImpl.java @@ -29,7 +29,7 @@ import java.util.Map; */ public class ResourceRegistrarImpl implements ResourceRegistrar { - private final Map> myResources = new HashMap>(); + private final Map> myResources = new HashMap>(); private final List myIgnored = new ArrayList(); public void addStdResource(@NonNls String resource, @NonNls String fileName) { @@ -41,9 +41,9 @@ public class ResourceRegistrarImpl implements ResourceRegistrar { } public void addStdResource(@NonNls String resource, @NonNls String version, @NonNls String fileName, @Nullable Class klass, @Nullable ClassLoader classLoader) { - final Map map = ExternalResourceManagerImpl.getMap(myResources, version, true); + final Map map = ExternalResourceManagerExImpl.getMap(myResources, version, true); assert map != null; - ExternalResourceManagerImpl.Resource res = new ExternalResourceManagerImpl.Resource(); + ExternalResourceManagerExImpl.Resource res = new ExternalResourceManagerExImpl.Resource(); res.file = fileName; res.classLoader = classLoader; res.clazz = klass; @@ -74,7 +74,7 @@ public class ResourceRegistrarImpl implements ResourceRegistrar { addStdResource(resource, version, ExternalResourceManagerEx.STANDARD_SCHEMAS + fileName, clazz); } - public Map> getResources() { + public Map> getResources() { return myResources; } diff --git a/xml/impl/src/com/intellij/javaee/XMLCatalogManager.java b/xml/xml-psi-impl/src/com/intellij/javaee/XMLCatalogManager.java similarity index 100% rename from xml/impl/src/com/intellij/javaee/XMLCatalogManager.java rename to xml/xml-psi-impl/src/com/intellij/javaee/XMLCatalogManager.java diff --git a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java index d844267fc124..cdf33c39eed7 100644 --- a/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java +++ b/xml/xml-psi-impl/src/com/intellij/xml/XmlCoreEnvironment.java @@ -7,10 +7,7 @@ import com.intellij.ide.highlighter.DTDFileType; import com.intellij.ide.highlighter.HtmlFileType; import com.intellij.ide.highlighter.XHtmlFileType; import com.intellij.ide.highlighter.XmlFileType; -import com.intellij.javaee.CoreExternalResourceManager; -import com.intellij.javaee.ExternalResourceManager; -import com.intellij.javaee.ExternalResourceManagerEx; -import com.intellij.javaee.ImplicitNamespaceDescriptorProvider; +import com.intellij.javaee.*; import com.intellij.lang.LanguageASTFactory; import com.intellij.lang.LanguageParserDefinitions; import com.intellij.lang.dtd.DTDLanguage; @@ -70,9 +67,12 @@ public class XmlCoreEnvironment { CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), XmlAttributeDescriptorsProvider.EP_NAME, XmlAttributeDescriptorsProvider.class); CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), XmlExtension.EP_NAME, XmlExtension.class); CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), HtmlEmbeddedTokenTypesProvider.EXTENSION_POINT_NAME, HtmlEmbeddedTokenTypesProvider.class); + CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), StandardResourceProvider.EP_NAME, StandardResourceProvider.class); + CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), StandardResourceEP.EP_NAME, StandardResourceEP.class); appEnvironment.addExtension(MetaDataContributor.EP_NAME, new XmlApplicationComponent()); appEnvironment.addExtension(FileBasedIndexExtension.EXTENSION_POINT_NAME, new XmlNamespaceIndex()); + appEnvironment.addExtension(StandardResourceProvider.EP_NAME, new InternalResourceProvider()); appEnvironment.registerApplicationService(ExternalResourceManager.class, createExternalResourceManager()); } diff --git a/xml/xml-psi-impl/xml-psi-impl.iml b/xml/xml-psi-impl/xml-psi-impl.iml index b12b84d69dcf..ea9932aed511 100644 --- a/xml/xml-psi-impl/xml-psi-impl.iml +++ b/xml/xml-psi-impl/xml-psi-impl.iml @@ -15,6 +15,7 @@ +