update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / javaee / ExternalResourceManagerImpl.java
blob04be2309fe92c44b498240696d1f0a30b77ae321
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.javaee;
18 import com.intellij.application.options.PathMacrosImpl;
19 import com.intellij.application.options.ReplacePathToMacroMap;
20 import com.intellij.openapi.components.ExpandMacroToPathMap;
21 import com.intellij.openapi.components.ServiceManager;
22 import com.intellij.openapi.components.State;
23 import com.intellij.openapi.components.Storage;
24 import com.intellij.openapi.diagnostic.Logger;
25 import com.intellij.openapi.extensions.Extensions;
26 import com.intellij.openapi.fileTypes.FileType;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.*;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.psi.PsiFile;
31 import com.intellij.psi.xml.XmlFile;
32 import com.intellij.util.ArrayUtil;
33 import com.intellij.util.NullableFunction;
34 import com.intellij.util.containers.HashMap;
35 import com.intellij.xml.XmlNSDescriptor;
36 import com.intellij.xml.XmlSchemaProvider;
37 import com.intellij.xml.util.XmlUtil;
38 import gnu.trove.THashSet;
39 import org.jdom.Element;
40 import org.jetbrains.annotations.NonNls;
41 import org.jetbrains.annotations.NotNull;
42 import org.jetbrains.annotations.Nullable;
44 import java.io.File;
45 import java.util.*;
47 /**
48 * @author mike
50 @State(name = "ExternalResourceManagerImpl",
51 storages = {@Storage(id = "other", file = "$APP_CONFIG$/other.xml")})
52 public class ExternalResourceManagerImpl extends ExternalResourceManagerEx implements JDOMExternalizable {
53 static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.openapi.impl.ExternalResourceManagerImpl");
55 @NonNls public static final String J2EE_1_3 = "http://java.sun.com/dtd/";
56 @NonNls public static final String J2EE_1_2 = "http://java.sun.com/j2ee/dtds/";
57 @NonNls public static final String J2EE_NS = "http://java.sun.com/xml/ns/j2ee/";
58 @NonNls public static final String JAVAEE_NS = "http://java.sun.com/xml/ns/javaee/";
61 private final Map<String, Map<String, String>> myResources = new HashMap<String, Map<String, String>>();
62 private final Set<String> myResourceLocations = new HashSet<String>();
64 private final Set<NullableFunction<String, XmlNSDescriptor>> myImplicitNamespaces =
65 new THashSet<NullableFunction<String, XmlNSDescriptor>>();
67 private final Set<String> myIgnoredResources = new HashSet<String>();
69 private final AtomicNotNullLazyValue<Map<String, Map<String, String>>> myStdResources = new AtomicNotNullLazyValue<Map<String, Map<String, String>>>() {
71 @NotNull
72 @Override
73 protected Map<String, Map<String, String>> compute() {
74 return computeStdResources();
78 protected Map<String, Map<String, String>> computeStdResources() {
79 ResourceRegistrarImpl registrar = new ResourceRegistrarImpl();
80 for (StandardResourceProvider provider : Extensions.getExtensions(StandardResourceProvider.EP_NAME)) {
81 provider.registerResources(registrar);
83 myIgnoredResources.addAll(registrar.getIgnored());
84 return registrar.getResources();
87 private final List<ExternalResourceListener> myListeners = new ArrayList<ExternalResourceListener>();
88 private long myModificationCount = 0;
89 private final PathMacrosImpl myPathMacros;
90 @NonNls private static final String RESOURCE_ELEMENT = "resource";
91 @NonNls private static final String URL_ATTR = "url";
92 @NonNls private static final String LOCATION_ATTR = "location";
93 @NonNls private static final String IGNORED_RESOURCE_ELEMENT = "ignored-resource";
94 private static final String DEFAULT_VERSION = null;
95 @NonNls public static final String STANDARD_SCHEMAS = "/standardSchemas/";
97 public ExternalResourceManagerImpl(PathMacrosImpl pathMacros) {
98 myPathMacros = pathMacros;
101 public static boolean isStandardResource(VirtualFile file) {
102 VirtualFile parent = file.getParent();
103 return parent != null && parent.getName().equals("standardSchemas");
106 public boolean isUserResource(VirtualFile file) {
107 return myResourceLocations.contains(file.getUrl());
110 @Nullable
111 static Map<String, String> getMap(@NotNull final Map<String, Map<String, String>> resources,
112 @Nullable final String version,
113 final boolean create) {
114 Map<String, String> map = resources.get(version);
115 if (map == null) {
116 if (create) {
117 map = new HashMap<String, String>();
118 resources.put(version, map);
120 else if (version == null || !version.equals(DEFAULT_VERSION)) {
121 map = resources.get(DEFAULT_VERSION);
125 return map;
128 public String getResourceLocation(String url) {
129 return getResourceLocation(url, DEFAULT_VERSION);
132 public String getResourceLocation(@NonNls String url, String version) {
133 Map<String, String> map = getMap(myResources, version, false);
134 String result = map != null ? map.get(url) : null;
136 if (result == null) {
137 map = getMap(myStdResources.getValue(), version, false);
138 result = map != null ? map.get(url) : null;
141 if (result == null) {
142 result = url;
145 return result;
148 public String getResourceLocation(@NonNls String url, @NotNull Project project) {
149 String location = getProjectResources(project).getResourceLocation(url);
150 return location == null || location.equals(url) ? getResourceLocation(url) : location;
153 public String getResourceLocation(@NonNls String url, String version, @NotNull Project project) {
154 String location = getProjectResources(project).getResourceLocation(url, version);
155 return location == null || location.equals(url) ? getResourceLocation(url, version) : location;
158 @Nullable
159 public PsiFile getResourceLocation(@NotNull @NonNls final String url, @NotNull final PsiFile baseFile, final String version) {
160 final XmlFile schema = XmlSchemaProvider.findSchema(url, baseFile);
161 if (schema != null) {
162 return schema;
164 final String location = getResourceLocation(url, version, baseFile.getProject());
165 return XmlUtil.findXmlFile(baseFile, location);
168 public String[] getResourceUrls(FileType fileType, final boolean includeStandard) {
169 return getResourceUrls(fileType, DEFAULT_VERSION, includeStandard);
172 public String[] getResourceUrls(@Nullable final FileType fileType, @NonNls final String version, final boolean includeStandard) {
173 final List<String> result = new LinkedList<String>();
174 addResourcesFromMap(fileType, result, version, myResources);
176 if (includeStandard) {
177 addResourcesFromMap(fileType, result, version, myStdResources.getValue());
180 return ArrayUtil.toStringArray(result);
183 private static void addResourcesFromMap(@Nullable final FileType fileType,
184 final List<String> result,
185 String version,
186 Map<String, Map<String, String>> resourcesMap) {
187 Map<String, String> resources = getMap(resourcesMap, version, false);
188 if (resources == null) return;
189 final Set<String> keySet = resources.keySet();
191 for (String key : keySet) {
192 String resource = resources.get(key);
194 if (fileType != null) {
195 String defaultExtension = fileType.getDefaultExtension();
197 if (resource.endsWith(defaultExtension) &&
198 resource.length() > defaultExtension.length() &&
199 resource.charAt(resource.length() - defaultExtension.length() - 1) == '.') {
200 result.add(key);
203 else {
204 result.add(key);
209 public void addResource(String url, String location) {
210 addResource(url, DEFAULT_VERSION, location);
213 public void addResource(@NonNls String url, @NonNls String version, @NonNls String location) {
214 addSilently(url, version, location);
215 fireExternalResourceChanged();
218 private void addSilently(String url, String version, String location) {
219 final Map<String, String> map = getMap(myResources, version, true);
220 assert map != null;
221 map.put(url, location);
222 myResourceLocations.add(location);
223 myModificationCount++;
226 public void removeResource(String url) {
227 removeResource(url, DEFAULT_VERSION);
230 public void removeResource(String url, String version) {
231 Map<String, String> map = getMap(myResources, version, false);
232 if (map != null) {
233 String location = map.remove(url);
234 if (location != null) {
235 myResourceLocations.remove(url);
237 myModificationCount++;
238 fireExternalResourceChanged();
242 @Override
243 public void removeResource(String url, @NotNull Project project) {
244 getProjectResources(project).removeResource(url);
247 @Override
248 public void addResource(@NonNls String url, @NonNls String location, @NotNull Project project) {
249 getProjectResources(project).addResource(url, location);
252 public String[] getAvailableUrls() {
253 Set<String> urls = new HashSet<String>();
254 for (Map<String, String> map : myResources.values()) {
255 urls.addAll(map.keySet());
257 return ArrayUtil.toStringArray(urls);
260 @Override
261 public String[] getAvailableUrls(Project project) {
262 return getProjectResources(project).getAvailableUrls();
265 public void clearAllResources() {
266 myResources.clear();
267 myIgnoredResources.clear();
270 public void clearAllResources(Project project) {
271 clearAllResources();
272 getProjectResources(project).clearAllResources();
273 myModificationCount++;
274 fireExternalResourceChanged();
277 public void addIgnoredResource(String url) {
278 addIgnoredSilently(url);
279 fireExternalResourceChanged();
282 private void addIgnoredSilently(String url) {
283 myIgnoredResources.add(url);
284 myModificationCount++;
287 public void removeIgnoredResource(String url) {
288 if (myIgnoredResources.remove(url)) {
289 myModificationCount++;
290 fireExternalResourceChanged();
294 public boolean isIgnoredResource(String url) {
295 return myIgnoredResources.contains(url) || isImplicitNamespaceDescriptor(url);
298 private static boolean isImplicitNamespaceDescriptor(String url) {
299 for (ImplicitNamespaceDescriptorProvider namespaceDescriptorProvider : Extensions
300 .getExtensions(ImplicitNamespaceDescriptorProvider.EP_NAME)) {
301 if (namespaceDescriptorProvider.getNamespaceDescriptor(null, url) != null) return true;
303 return false;
306 public String[] getIgnoredResources() {
307 return ArrayUtil.toStringArray(myIgnoredResources);
310 public long getModificationCount() {
311 return myModificationCount;
314 public void readExternal(Element element) throws InvalidDataException {
315 final ExpandMacroToPathMap macroExpands = new ExpandMacroToPathMap();
316 myPathMacros.addMacroExpands(macroExpands);
317 macroExpands.substitute(element, SystemInfo.isFileSystemCaseSensitive);
319 myModificationCount++;
320 for (final Object o1 : element.getChildren(RESOURCE_ELEMENT)) {
321 Element e = (Element)o1;
322 addSilently(e.getAttributeValue(URL_ATTR), DEFAULT_VERSION, e.getAttributeValue(LOCATION_ATTR).replace('/', File.separatorChar));
325 for (final Object o : element.getChildren(IGNORED_RESOURCE_ELEMENT)) {
326 Element e = (Element)o;
327 addIgnoredSilently(e.getAttributeValue(URL_ATTR));
331 public void writeExternal(Element element) throws WriteExternalException {
332 final String[] urls = getAvailableUrls();
333 for (String url : urls) {
334 if (url == null) continue;
335 String location = getResourceLocation(url);
336 if (location == null) continue;
337 final Element e = new Element(RESOURCE_ELEMENT);
339 e.setAttribute(URL_ATTR, url);
340 e.setAttribute(LOCATION_ATTR, location.replace(File.separatorChar, '/'));
341 element.addContent(e);
344 final String[] ignoredResources = getIgnoredResources();
345 for (String ignoredResource : ignoredResources) {
346 final Element e = new Element(IGNORED_RESOURCE_ELEMENT);
348 e.setAttribute(URL_ATTR, ignoredResource);
349 element.addContent(e);
352 final ReplacePathToMacroMap macroReplacements = new ReplacePathToMacroMap();
353 PathMacrosImpl.getInstanceEx().addMacroReplacements(macroReplacements);
354 macroReplacements.substitute(element, SystemInfo.isFileSystemCaseSensitive);
357 public void addExternalResourceListener(ExternalResourceListener listener) {
358 myListeners.add(listener);
361 public void removeExternalResourceListener(ExternalResourceListener listener) {
362 myListeners.remove(listener);
365 private void fireExternalResourceChanged() {
366 for (ExternalResourceListener listener : myListeners.toArray(new ExternalResourceListener[myListeners.size()])) {
367 listener.externalResourceChanged();
371 private static ExternalResourceManagerImpl getProjectResources(Project project) {
372 return ServiceManager.getService(project, ProjectResources.class);