update copyright
[fedora-idea.git] / xml / impl / src / com / intellij / xml / util / XmlResourceResolver.java
blob11fdea2a04512b39b38109f6abc6660bac1f3a91
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.xml.util;
18 import com.intellij.javaee.ExternalResourceManagerEx;
19 import com.intellij.javaee.ExternalResourceManager;
20 import com.intellij.javaee.UriUtil;
21 import com.intellij.openapi.application.ApplicationManager;
22 import com.intellij.openapi.diagnostic.Logger;
23 import com.intellij.openapi.project.Project;
24 import com.intellij.openapi.util.text.StringUtil;
25 import com.intellij.openapi.vfs.VfsUtil;
26 import com.intellij.openapi.vfs.VirtualFile;
27 import com.intellij.openapi.vfs.VirtualFileManager;
28 import com.intellij.openapi.vfs.ex.http.HttpFileSystem;
29 import com.intellij.psi.PsiFile;
30 import com.intellij.psi.PsiManager;
31 import com.intellij.psi.impl.source.resolve.reference.impl.providers.URIReferenceProvider;
32 import com.intellij.psi.xml.XmlFile;
33 import com.intellij.psi.xml.XmlDocument;
34 import com.intellij.psi.xml.XmlTag;
35 import com.intellij.xml.actions.ValidateXmlActionHandler;
36 import com.intellij.xml.XmlBundle;
37 import org.apache.xerces.xni.XMLResourceIdentifier;
38 import org.apache.xerces.xni.XNIException;
39 import org.apache.xerces.xni.parser.XMLEntityResolver;
40 import org.apache.xerces.xni.parser.XMLInputSource;
41 import org.jetbrains.annotations.NonNls;
42 import org.jetbrains.annotations.Nullable;
43 import org.xml.sax.SAXParseException;
45 import java.io.File;
46 import java.io.IOException;
47 import java.io.StringReader;
48 import java.net.MalformedURLException;
49 import java.net.URL;
50 import java.util.HashMap;
51 import java.util.Map;
53 /**
54 * Created by IntelliJ IDEA.
55 * User: Maxim.Mossienko
56 * Date: Aug 6, 2004
57 * Time: 6:48:55 PM
58 * To change this template use File | Settings | File Templates.
60 public class XmlResourceResolver implements XMLEntityResolver {
61 private static final Logger LOG = Logger.getInstance("#com.intellij.xml.util.XmlResourceResolver");
62 private final XmlFile myFile;
63 private final Project myProject;
64 private final Map<String,String> myExternalResourcesMap = new HashMap<String, String>(1);
65 private boolean myStopOnUnDeclaredResource;
66 @NonNls
67 public static final String FILE_PREFIX = "file://";
68 private final ValidateXmlActionHandler.ErrorReporter myErrorReporter;
70 public XmlResourceResolver(XmlFile _xmlFile, Project _project, final ValidateXmlActionHandler.ErrorReporter errorReporter) {
71 myFile = _xmlFile;
72 myProject = _project;
73 myErrorReporter = errorReporter;
76 public String getPathByPublicId(String baseId) {
77 return myExternalResourcesMap.get(baseId);
80 public String[] getResourcePaths() {
81 return myExternalResourcesMap.values().toArray(new String[myExternalResourcesMap.size()]);
84 @Nullable
85 public PsiFile resolve(final String baseSystemId, final String _systemId) {
86 if (LOG.isDebugEnabled()) {
87 LOG.debug("enter: resolveEntity(baseSystemId='" + baseSystemId + "' systemId='" + _systemId + "," + super.toString() + "')");
90 if (_systemId == null) return null;
91 if (myStopOnUnDeclaredResource &&
92 ExternalResourceManagerEx.getInstanceEx().isIgnoredResource(_systemId)) {
93 throw new IgnoredResourceException();
96 final int length = URIReferenceProvider.getPrefixLength(_systemId);
97 final String systemId = _systemId.substring(length);
99 final PsiFile[] result = new PsiFile[] { null };
100 final Runnable action = new Runnable() {
101 public void run() {
102 PsiFile baseFile = null;
103 VirtualFile vFile = null;
105 if (baseSystemId != null) {
106 baseFile = resolve(null,baseSystemId);
108 if (baseFile == null) {
109 if (myFile != null) {
110 // Find relative to myFile
111 File workingFile = new File("");
112 String workingDir = workingFile.getAbsoluteFile().getAbsolutePath().replace(File.separatorChar, '/');
113 String id = StringUtil.replace(baseSystemId, workingDir, myFile.getVirtualFile().getParent().getPath());
114 vFile = UriUtil.findRelativeFile(id, (VirtualFile)null);
117 if (vFile == null) {
118 vFile = UriUtil.findRelativeFile(baseSystemId, (VirtualFile)null);
120 if (vFile == null) {
121 try {
122 vFile = VfsUtil.findFileByURL(new URL(baseSystemId));
123 } catch(MalformedURLException ex) {}
128 if (vFile != null && !vFile.isDirectory() && !(vFile.getFileSystem() instanceof HttpFileSystem)) {
129 baseFile = PsiManager.getInstance(myProject).findFile(vFile);
132 if (baseFile == null) {
133 baseFile = myFile;
136 String version = null;
137 if (baseFile == myFile) {
138 final XmlDocument document = myFile.getDocument();
139 final XmlTag rootTag = document != null ? document.getRootTag():null;
140 version = rootTag != null ? rootTag.getAttributeValue("version"):null;
143 PsiFile psiFile = ExternalResourceManager.getInstance().getResourceLocation(systemId, baseFile, version);
144 if (psiFile == null) {
145 psiFile = XmlUtil.findXmlFile(baseFile, systemId);
148 if (psiFile == null && baseSystemId != null) {
149 String fullUrl = baseSystemId.substring( 0, baseSystemId.lastIndexOf('/') + 1 ) + systemId;
150 psiFile = XmlUtil.findXmlFile(baseFile,fullUrl);
153 if (LOG.isDebugEnabled()) {
154 LOG.debug("before relative file checking:"+psiFile+","+systemId+","+ baseSystemId+")");
156 if (psiFile == null && baseSystemId == null) { // entity file
157 File workingFile = new File("");
158 String workingDir = workingFile.getAbsoluteFile().getAbsolutePath().replace(File.separatorChar, '/') + "/";
160 String relativePath = StringUtil.replace(
161 systemId,
162 workingDir,
166 if (relativePath.equals(systemId)) {
167 // on Windows systemId consisting of idea install path could become encoded DOS short name (e.g. idea%7f1.504)
168 // I am not aware how to get such name from 'workingDir' so let just pickup filename from there
169 relativePath = systemId.substring(systemId.lastIndexOf('/') + 1);
172 if (LOG.isDebugEnabled()) {
173 LOG.debug("next to relative file checking:"+relativePath+","+myExternalResourcesMap.size()+")");
176 for(String path:myExternalResourcesMap.values()) {
177 if (LOG.isDebugEnabled()) {
178 LOG.debug("Finding file by url:" + path);
180 VirtualFile file = VirtualFileManager.getInstance().findFileByUrl(path);
181 if (file == null) continue;
182 if (LOG.isDebugEnabled()) {
183 LOG.debug("Finding "+relativePath+" relative to:"+file.getPath());
185 final VirtualFile relativeFile = UriUtil.findRelativeFile(relativePath, file);
186 if (LOG.isDebugEnabled()) {
187 LOG.debug("Found "+(relativeFile != null ? relativeFile.getPath():"null"));
190 if (relativeFile != null) {
191 psiFile = PsiManager.getInstance(myProject).findFile(relativeFile);
192 if (psiFile != null) break;
197 if (LOG.isDebugEnabled()) {
198 LOG.debug("resolveEntity: psiFile='" + (psiFile != null ? psiFile.getVirtualFile() : null) + "'");
200 result[0] = psiFile;
203 ApplicationManager.getApplication().runReadAction(action);
205 final PsiFile psiFile = result[0];
206 if (psiFile != null) {
207 final String url = psiFile.getVirtualFile().getUrl();
208 if (LOG.isDebugEnabled()) {
209 LOG.debug("Adding external resource ref:"+systemId+","+url+","+super.toString());
211 myExternalResourcesMap.put(systemId,url);
213 return psiFile;
216 @Nullable
217 public XMLInputSource resolveEntity(XMLResourceIdentifier xmlResourceIdentifier) throws XNIException, IOException {
218 String publicId = xmlResourceIdentifier.getLiteralSystemId() != null ?
219 xmlResourceIdentifier.getLiteralSystemId():
220 xmlResourceIdentifier.getNamespace();
222 PsiFile psiFile = resolve(xmlResourceIdentifier.getBaseSystemId(), publicId);
223 if (psiFile == null && xmlResourceIdentifier.getBaseSystemId() != null) {
224 psiFile = ExternalResourceManager.getInstance().getResourceLocation(xmlResourceIdentifier.getBaseSystemId(), myFile, null);
226 if (psiFile==null && xmlResourceIdentifier.getLiteralSystemId()!=null && xmlResourceIdentifier.getNamespace()!=null) {
227 psiFile = resolve(
228 xmlResourceIdentifier.getBaseSystemId(),
229 publicId = xmlResourceIdentifier.getNamespace()
233 if (psiFile == null) {
234 if (publicId != null && publicId.indexOf(":/") != -1) {
235 myErrorReporter.processError(
236 new SAXParseException(XmlBundle.message("xml.validate.external.resource.is.not.registered", publicId), publicId, null, 0,0), false);
237 final XMLInputSource source = new XMLInputSource(xmlResourceIdentifier);
238 source.setPublicId(publicId);
239 source.setCharacterStream(new StringReader(""));
240 return source;
242 return null;
245 XMLInputSource source = new XMLInputSource(xmlResourceIdentifier);
246 if (xmlResourceIdentifier.getLiteralSystemId() == null) {
247 VirtualFile virtualFile = psiFile.getVirtualFile();
248 final String url = VfsUtil.fixIDEAUrl(virtualFile.getUrl());
249 source.setBaseSystemId(url);
250 source.setSystemId(url);
252 source.setPublicId(publicId);
253 source.setCharacterStream(new StringReader(psiFile.getText()));
255 return source;
258 public void setStopOnUnDeclaredResource(final boolean stopOnUnDeclaredResource) {
259 myStopOnUnDeclaredResource = stopOnUnDeclaredResource;
262 public static class IgnoredResourceException extends RuntimeException {