Skip to content

Commit

Permalink
Fix bug with custom protocol which doesn't load content model.
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
azerr authored and angelozerr committed Oct 12, 2020
1 parent f0503e2 commit 55ad380
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 21 deletions.
Expand Up @@ -237,8 +237,7 @@ private void fillReferencedGrammarInfo(DOMDocument document, String publicId, St
boolean downloading = false;
Exception cacheError = null;
String resolvedUri = resolvedURIInfo.getResolvedURI();
boolean isFileResource = URIUtils.isFileResource(resolvedUri);
if (!isFileResource && cacheResolverExtension.isUseCache()) {
if (cacheResolverExtension.canUseCache(resolvedUri)) {
// The DTD/XML Schema comes from http://, ftp:// etc and cache manager is
// activated
// Try to load the DTD/XML Schema with the cache manager
Expand Down Expand Up @@ -301,8 +300,7 @@ private CMDocument findCMDocument(String uri, String publicId, String systemId,
if (cmDocument != null) {
return cmDocument;
}
boolean isFileResource = URIUtils.isFileResource(resolvedUri);
if (!isFileResource && cacheResolverExtension.isUseCache()) {
if (cacheResolverExtension.canUseCache(resolvedUri)) {
// The DTD/XML Schema comes from http://, ftp:// etc and cache manager is
// activated
// Try to load the DTD/XML Schema with the cache manager
Expand Down
Expand Up @@ -93,7 +93,7 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
*/
public Path getCachedResource(String url) throws IOException, CacheResourceDownloadedException {
// Cache is used only for resource coming from "http(s)" or "ftp".
if (cacheResourcesManager.canUseCache(url)) {
if (canUseCache(url)) {
// Try to get the downloaded resource. In the case where the resource is
// downloading but takes too long, a CacheResourceDownloadingException is
// thrown.
Expand All @@ -102,6 +102,18 @@ public Path getCachedResource(String url) throws IOException, CacheResourceDownl
return null;
}

/**
* Returns <code>true</code> if cache is enabled and url comes from "http(s)" or
* "ftp" and <code>false</code> otherwise.
*
* @param url
* @return <code>true</code> if cache is enabled and url comes from "http(s)" or
* "ftp" and <code>false</code> otherwise.
*/
public boolean canUseCache(String url) {
return cacheResourcesManager.canUseCache(url);
}

/**
* Set <code>true</code> if cache must be used, <code>false</code> otherwise.
*
Expand Down
Expand Up @@ -27,14 +27,15 @@
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.eclipse.lemminx.utils.FilesUtils;
import org.eclipse.lemminx.utils.URIUtils;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
Expand All @@ -52,6 +53,8 @@ public class CacheResourcesManager {
private final Map<String, CompletableFuture<Path>> resourcesLoading;
private boolean useCache;

private final Set<String> protocolsForCahe;

class ResourceInfo {

String resourceURI;
Expand Down Expand Up @@ -96,7 +99,8 @@ public ResourceToDeploy(URI resourceURI, String resourceFromClasspath) {
}

/**
* @return The computed path in the lemmix cache that the resource will be stored at
* @return The computed path in the lemmix cache that the resource will be
* stored at
*/
public Path getDeployedPath() throws IOException {
return FilesUtils.getDeployedPath(resourceCachePath);
Expand All @@ -116,7 +120,9 @@ public CacheResourcesManager() {

public CacheResourcesManager(Cache<String, Boolean> cache) {
resourcesLoading = new HashMap<>();
protocolsForCahe = new HashSet<>();
unavailableURICache = cache;
addDefaultProtocolsForCache();
}

public Path getResource(final String resourceURI) throws IOException {
Expand Down Expand Up @@ -244,7 +250,7 @@ public static Path getResourceCachePath(ResourceToDeploy resource) throws IOExce
* "ftp" and <code>false</code> otherwise.
*/
public boolean canUseCache(String url) {
return isUseCache() && URIUtils.isRemoteResource(url);
return isUseCache() && isUseCacheFor(url);
}

/**
Expand All @@ -267,4 +273,63 @@ public void setUseCache(boolean useCache) {
public boolean isUseCache() {
return useCache;
}

/**
* Add protocol for using cache when url will start with the given protocol.
*
* @param protocol the protocol to add.
*/
public void addProtocolForCahe(String protocol) {
protocolsForCahe.add(formatProtocol(protocol));
}

/**
* Remove protocol to avoid using cache when url will start with the given
* protocol.
*
* @param protocol the protocol to remove.
*/
public void removeProtocolForCahe(String protocol) {
protocolsForCahe.remove(formatProtocol(protocol));
}

/**
* Add ':' separator if the given protocol doesn't contain it.
*
* @param protocol the protocol to format.
*
* @return the protocol concat with ':'.
*/
private static String formatProtocol(String protocol) {
if (!protocol.endsWith(":")) {
return protocol + ":";
}
return protocol;
}

/**
* Returns true if the cache must be used for the given url and false otherwise.
*
* @param url the url.
*
* @return true if the cache must be used for the given url and false otherwise.
*/
private boolean isUseCacheFor(String url) {
for (String protocol : protocolsForCahe) {
if (url.startsWith(protocol)) {
return true;
}
}
return false;
}

/**
* Add http, https, ftp protocol to use cache.
*/
private void addDefaultProtocolsForCache() {
addProtocolForCahe("http");
addProtocolForCahe("https");
addProtocolForCahe("ftp");
}

}
Expand Up @@ -19,19 +19,6 @@ public class URIUtils {
private URIUtils() {
}

/**
* Returns <code>true</code> if the given URL is a remote resource,
* <code>false</code> otherwise.
*
* @param resourceURI
* @return <code>true</code> if the given URL is a remote resource, false
* otherwise.
*/
public static boolean isRemoteResource(String resourceURI) {
return resourceURI != null && (resourceURI.startsWith("http:") || resourceURI.startsWith("https:")
|| resourceURI.startsWith("ftp:"));
}

/**
* Returns <code>true</code> if the given URL is a file resource,
* <code>false</code> otherwise.
Expand Down
Expand Up @@ -17,17 +17,24 @@
import static org.eclipse.lemminx.XMLAssert.te;

import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.URLStreamHandlerFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.function.Consumer;

import org.apache.xerces.impl.XMLEntityManager;
import org.apache.xerces.util.URI.MalformedURIException;
import org.eclipse.lemminx.XMLAssert;
import org.eclipse.lemminx.commons.BadLocationException;
import org.eclipse.lemminx.extensions.contentmodel.model.ContentModelManager;
import org.eclipse.lemminx.services.XMLLanguageService;
import org.eclipse.lemminx.settings.SharedSettings;
import org.eclipse.lemminx.uriresolver.URIResolverExtension;
import org.eclipse.lsp4j.CompletionCapabilities;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemCapabilities;
Expand Down Expand Up @@ -1226,4 +1233,54 @@ private void testCompletionSnippetSupportFor(String xml, String fileURI, Integer
XMLAssert.testCompletionFor(new XMLLanguageService(), xml, null, null, fileURI, null, sharedSettings,
expectedItems);
}

@Test
public void customProtocolNamespaceSchemaLocationCompletionWhenCachingOn() throws BadLocationException {

URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() {

@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
if ("custom".equals(protocol)) {
return new URLStreamHandler() {

@Override
protected URLConnection openConnection(URL u) throws IOException {
return XMLSchemaCompletionExtensionsTest.class.getResource(u.getPath()).openConnection();
}
};
}
return null;
}
});

Consumer<XMLLanguageService> config = service -> {
ContentModelManager contentModelManager = service.getComponent(ContentModelManager.class);

contentModelManager.setUseCache(true);

service.getResolverExtensionManager().registerResolver(new URIResolverExtension() {

@Override
public String resolve(String baseLocation, String publicId, String systemId) {
if ("test://schema/format".equals(publicId)) {
return "custom://test/xsd/Format.xsd";
}
return null;
}

});
};


String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + //
"<Configuration xmlns=\"test://schema/format\">\r\n"
+ //
" <ViewDefinitions>\r\n" + //
" <View><|";
// Completion only with Name
XMLAssert.testCompletionFor(new XMLLanguageService(), xml, (String) null, config, "src/test/resources/Format.xml", 4 + 2 /* CDATA and Comments */, true,
c("Name", "<Name></Name>"), c("End with '</Configuration>'", "/Configuration>"),
c("End with '</ViewDefinitions>'", "/ViewDefinitions>"), c("End with '</View>'", "/View>"));
}
}

0 comments on commit 55ad380

Please sign in to comment.