From 39eefb7a3721bfd6d37ea3fbd83dad227e28d8c3 Mon Sep 17 00:00:00 2001 From: Jessica He Date: Wed, 3 Aug 2022 20:22:10 -0400 Subject: [PATCH] Report error on invalid catalog URI Signed-off-by: Jessica He --- .../extensions/catalog/CatalogUtils.java | 24 ++++++ .../XMLCatalogDiagnosticsParticipant.java | 58 +++++++++++++++ .../XMLCatalogDocumentLinkParticipant.java | 23 +----- .../catalog/XMLCatalogErrorCode.java | 35 +++++++++ .../extensions/catalog/XMLCatalogPlugin.java | 5 ++ .../org/eclipse/lemminx/utils/FilesUtils.java | 14 ++++ .../catalog/XMLCatalogDiagnosticsTest.java | 74 +++++++++++++++++++ 7 files changed, 211 insertions(+), 22 deletions(-) create mode 100644 org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsParticipant.java create mode 100644 org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogErrorCode.java create mode 100644 org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsTest.java diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java index 73c23bb5e..0c11897dc 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/CatalogUtils.java @@ -17,11 +17,15 @@ import java.util.Collections; import java.util.List; +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.util.URI.MalformedURIException; import org.eclipse.lemminx.dom.DOMAttr; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.dom.DOMElement; import org.eclipse.lemminx.dom.DOMNode; import org.eclipse.lemminx.utils.DOMUtils; +import org.eclipse.lemminx.utils.FilesUtils; +import org.eclipse.lemminx.utils.StringUtils; import org.eclipse.lsp4j.jsonrpc.validation.NonNull; /** @@ -195,4 +199,24 @@ private static CatalogEntry createCatalogEntry(@NonNull String baseURI, DOMEleme return null; } + /** + * Returns the expanded system location + * + * @param document the xml document + * @param catalogEntry the catalog entry + * @return the expanded system location + */ + public static String getResolvedLocation(DOMDocument document, CatalogEntry catalogEntry) { + String location = catalogEntry.getResolvedURI(); + + if (StringUtils.isBlank(location)) { + return null; + } + try { + return XMLEntityManager.expandSystemId(location, FilesUtils.removeFileScheme(document.getDocumentURI()), + false); + } catch (MalformedURIException e) { + return location; + } + } } \ No newline at end of file diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsParticipant.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsParticipant.java new file mode 100644 index 000000000..f2bea7df6 --- /dev/null +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsParticipant.java @@ -0,0 +1,58 @@ +/******************************************************************************* +* Copyright (c) 2022 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ + +package org.eclipse.lemminx.extensions.catalog; + +import java.text.MessageFormat; +import java.util.List; + +import org.eclipse.lemminx.dom.DOMDocument; +import org.eclipse.lemminx.extensions.contentmodel.settings.XMLValidationSettings; +import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant; +import org.eclipse.lemminx.utils.DOMUtils; +import org.eclipse.lemminx.utils.FilesUtils; +import org.eclipse.lemminx.utils.URIUtils; +import org.eclipse.lemminx.utils.XMLPositionUtility; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; + +/** + * Validate XML catalog. + * + */ +public class XMLCatalogDiagnosticsParticipant implements IDiagnosticsParticipant { + + private static final String ERROR_STRING = "The file ''{0}'' cannot be found."; + + @Override + public void doDiagnostics(DOMDocument xmlDocument, List diagnostics, + XMLValidationSettings validationSettings, CancelChecker monitor) { + if (!DOMUtils.isCatalog(xmlDocument)) { + return; + } + + for (CatalogEntry catalogEntry : CatalogUtils.getCatalogEntries(xmlDocument)) { + // CatalogUtils.getResolvedLocation() always returns path with 'file://' scheme, + // appending it in the case when original URI does not start with 'file://'. + // Ex: originalURI ="foo/bar.xsd" -> path ="file://foo/bar.xsd" + String path = CatalogUtils.getResolvedLocation(xmlDocument, catalogEntry); + if (!FilesUtils.isValidPath(FilesUtils.getPath(path)) && URIUtils.isFileResource(path)) { + Range range = XMLPositionUtility.selectValueWithoutQuote(catalogEntry.getLinkRange()); + String msg = MessageFormat.format(ERROR_STRING, catalogEntry.getResolvedURI()); + + diagnostics + .add(new Diagnostic(range, msg, DiagnosticSeverity.Error, xmlDocument.getDocumentURI(), + XMLCatalogErrorCode.catalog_uri.name())); + } + } + } +} diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java index 217ccc431..9e8faae7e 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDocumentLinkParticipant.java @@ -14,13 +14,9 @@ import java.util.logging.Level; import java.util.logging.Logger; -import org.apache.xerces.impl.XMLEntityManager; -import org.apache.xerces.util.URI.MalformedURIException; import org.eclipse.lemminx.commons.BadLocationException; import org.eclipse.lemminx.dom.DOMDocument; import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; -import org.eclipse.lemminx.utils.FilesUtils; -import org.eclipse.lemminx.utils.StringUtils; import org.eclipse.lemminx.utils.XMLPositionUtility; import org.eclipse.lsp4j.DocumentLink; @@ -52,8 +48,7 @@ public void findDocumentLinks(DOMDocument document, List links) { */ private static DocumentLink createDocumentLinkFromCatalogEntry(DOMDocument document, CatalogEntry catalogEntry) { try { - String path = getResolvedLocation(FilesUtils.removeFileScheme(document.getDocumentURI()), - catalogEntry.getResolvedURI()); + String path = CatalogUtils.getResolvedLocation(document, catalogEntry); if (path != null && catalogEntry.getLinkRange() != null) { return XMLPositionUtility.createDocumentLink(catalogEntry.getLinkRange(), path, true); } @@ -63,20 +58,4 @@ private static DocumentLink createDocumentLinkFromCatalogEntry(DOMDocument docum return null; } - /** - * Returns the expanded system location - * - * @return the expanded system location - */ - private static String getResolvedLocation(String documentURI, String location) { - if (StringUtils.isBlank(location)) { - return null; - } - try { - return XMLEntityManager.expandSystemId(location, documentURI, false); - } catch (MalformedURIException e) { - return location; - } - } - } \ No newline at end of file diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogErrorCode.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogErrorCode.java new file mode 100644 index 000000000..473918c15 --- /dev/null +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogErrorCode.java @@ -0,0 +1,35 @@ +/******************************************************************************* +* Copyright (c) 2022 Red Hat Inc. and others. +* All rights reserved. This program and the accompanying materials +* which accompanies this distribution, and is available at +* http://www.eclipse.org/legal/epl-v20.html +* +* Contributors: +* Red Hat Inc. - initial API and implementation +*******************************************************************************/ + +package org.eclipse.lemminx.extensions.catalog; + +import org.eclipse.lemminx.services.extensions.diagnostics.IXMLErrorCode; + +/** + * XML Catalog error code. + * + */ +public enum XMLCatalogErrorCode implements IXMLErrorCode { + catalog_uri("catalog_uri"); + + private final String code; + + private XMLCatalogErrorCode(String code) { + this.code = code; + } + + @Override + public String getCode() { + if (code == null) { + return name(); + } + return code; + } +} diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java index 6455cf0b3..6b894b49b 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogPlugin.java @@ -24,6 +24,7 @@ import org.eclipse.lemminx.services.extensions.IDocumentLinkParticipant; import org.eclipse.lemminx.services.extensions.IXMLExtension; import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry; +import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant; import org.eclipse.lemminx.services.extensions.save.ISaveContext; import org.eclipse.lemminx.utils.FilesUtils; import org.eclipse.lsp4j.InitializeParams; @@ -35,11 +36,13 @@ public class XMLCatalogPlugin implements IXMLExtension { private XMLCatalogURIResolverExtension uiResolver; private final IDocumentLinkParticipant documentLinkParticipant; + private final IDiagnosticsParticipant diagnosticsParticipant; private InvalidPathWarner pathWarner; public XMLCatalogPlugin() { documentLinkParticipant = new XMLCatalogDocumentLinkParticipant(); + diagnosticsParticipant = new XMLCatalogDiagnosticsParticipant(); } @Override @@ -61,11 +64,13 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) { this.pathWarner = new InvalidPathWarner(notificationService); } registry.registerDocumentLinkParticipant(documentLinkParticipant); + registry.registerDiagnosticsParticipant(diagnosticsParticipant); } @Override public void stop(XMLExtensionsRegistry registry) { registry.getResolverExtensionManager().unregisterResolver(uiResolver); + registry.unregisterDiagnosticsParticipant(diagnosticsParticipant); } private void validateCatalogPaths(ContentModelSettings cmSettings) { diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/FilesUtils.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/FilesUtils.java index 5e874444c..6fc3548be 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/FilesUtils.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/utils/FilesUtils.java @@ -289,4 +289,18 @@ public static String encodePath(String path) { public static String readString(Path path) throws IOException { return Files.readAllLines(path).stream().collect(Collectors.joining(System.lineSeparator())); } + + /** + * Returns true if the file at the given path exists. + * + * @param path the path. + * + * @return true if the file at the given path exists. + */ + public static boolean isValidPath(Path path){ + if (Files.exists(path)) { + return true; + } + return false; + } } diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsTest.java new file mode 100644 index 000000000..1962f827e --- /dev/null +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/catalog/XMLCatalogDiagnosticsTest.java @@ -0,0 +1,74 @@ +package org.eclipse.lemminx.extensions.catalog; + +import static org.eclipse.lemminx.XMLAssert.d; + +import org.eclipse.lemminx.XMLAssert; +import org.junit.jupiter.api.Test; + +public class XMLCatalogDiagnosticsTest { + @Test + public void testCatalogWithValidFile() { + String xml = "\n" + // + "\n" + // + "" + // + ""; + XMLAssert.testDiagnosticsFor(xml); + } + + @Test + public void testCatalogWithInvalidFile() { + String xml = "\n" + // + "\n" + // + "" + // + ""; + XMLAssert.testDiagnosticsFor(xml, d(3, 5, 3, 53, XMLCatalogErrorCode.catalog_uri)); + } + + @Test + public void testCatalogWithHttpLink() { + String xml = "\n" + // + "\n" + // + "" + // + ""; + XMLAssert.testDiagnosticsFor(xml); + } + + @Test + public void testCatalogEntryWithXMLBaseGroupValidFile() { + String xml = "\n" + // + " \n" + // + " \n" + // + " " + // + " " + // + " "; + XMLAssert.testDiagnosticsFor(xml); + } + + @Test + public void testCatalogEntryWithXMLBaseGroupInvalidFile() { + String xml = "\n" + // + " \n" + // + " \n" + // + " " + // + " " + // + " "; + XMLAssert.testDiagnosticsFor(xml, d(4, 11, 4, 36, XMLCatalogErrorCode.catalog_uri)); + } + + @Test + public void testCatalogEntryWithXMLBaseGroupInvalidBase() { + String xml = "\n" + // + " \n" + // + " \n" + // + " " + // + " " + // + " "; + XMLAssert.testDiagnosticsFor(xml, d(4, 11, 4, 31, XMLCatalogErrorCode.catalog_uri)); + } +} \ No newline at end of file