Validate XML for reports

Report warnings etc. to error log.

Change-Id: Ia848962faac0d00b4a36bcb71b75283ec9927623
diff --git a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
index c33389b..038c7fa 100644
--- a/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
+++ b/plugins/org.eclipse.mat.hprof/src/org/eclipse/mat/hprof/acquire/JMapHeapDumpProvider.java
@@ -482,6 +482,8 @@
             SAXParser parser = parserFactory.newSAXParser();

             XMLReader saxXmlReader =  parser.getXMLReader();

             saxXmlReader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); //$NON-NLS-1$

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); //$NON-NLS-1$

             saxXmlReader.setContentHandler(handler);

             saxXmlReader.setErrorHandler(handler);

             saxXmlReader.parse(new InputSource(new StringReader(input)));

diff --git a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
index 2e447f4..2d969f0 100644
--- a/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
+++ b/plugins/org.eclipse.mat.ibmdumps/src/org/eclipse/mat/ibmvm/acquire/IBMExecDumpProvider.java
@@ -527,6 +527,8 @@
             SAXParser parser = parserFactory.newSAXParser();

             XMLReader saxXmlReader =  parser.getXMLReader();

             saxXmlReader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); //$NON-NLS-1$

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); //$NON-NLS-1$

             saxXmlReader.setContentHandler(handler);

             saxXmlReader.setErrorHandler(handler);

             saxXmlReader.parse(new InputSource(new StringReader(input)));

diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/SpecFactory.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/SpecFactory.java
index 4afe814..0095955 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/SpecFactory.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/SpecFactory.java
@@ -19,6 +19,7 @@
 import java.io.InputStream;

 import java.net.URL;

 import java.util.LinkedList;

+import java.util.List;

 import java.util.logging.Level;

 import java.util.logging.Logger;

 

@@ -26,6 +27,8 @@
 import javax.xml.parsers.ParserConfigurationException;

 import javax.xml.parsers.SAXParser;

 import javax.xml.parsers.SAXParserFactory;

+import javax.xml.validation.Schema;

+import javax.xml.validation.SchemaFactory;

 

 import org.eclipse.core.runtime.CoreException;

 import org.eclipse.core.runtime.IConfigurationElement;

@@ -38,6 +41,7 @@
 import org.xml.sax.Attributes;

 import org.xml.sax.InputSource;

 import org.xml.sax.SAXException;

+import org.xml.sax.SAXParseException;

 import org.xml.sax.XMLReader;

 import org.xml.sax.helpers.DefaultHandler;

 

@@ -183,14 +187,21 @@
     {

         try

         {

-            SpecHandler handler = new SpecHandler(bundle);

+            SpecHandler handler = new SpecHandler(bundle, source);

             SAXParserFactory parserFactory = SAXParserFactory.newInstance();

             parserFactory.setNamespaceAware(true);

+            // Add schema validation

+            URL url = ReportPlugin.getDefault().getBundle().getResource("schema/report.xsd"); //$NON-NLS-1$

+            SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);

+            Schema schema = factory.newSchema(url);

+            parserFactory.setSchema(schema);

             SAXParser parser = parserFactory.newSAXParser();

             XMLReader saxXmlReader =  parser.getXMLReader();

             // Old way is deprecated

             //saxXmlReader = XMLReaderFactory.createXMLReader();

             saxXmlReader.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); //$NON-NLS-1$

+            saxXmlReader.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); //$NON-NLS-1$

             saxXmlReader.setContentHandler(handler);

             saxXmlReader.setErrorHandler(handler);

             saxXmlReader.parse(new InputSource(input));

@@ -215,12 +226,14 @@
         private Bundle bundle;

         private LinkedList<Spec> stack;

         private StringBuilder buf;

+        private Object source;

 

-        private SpecHandler(Bundle bundle)

+        private SpecHandler(Bundle bundle, Object source)

         {

             this.bundle = bundle;

             this.stack = new LinkedList<Spec>();

             this.stack.add(new SectionSpec("root")); //$NON-NLS-1$

+            this.source = source;

         }

 

         @SuppressWarnings("nls")

@@ -302,6 +315,27 @@
         }

 

         @Override

+        public void warning(SAXParseException e)

+        {

+            // Just log the warning

+            Logger.getLogger(getClass().getName()).log(Level.INFO, MessageUtil.format(Messages.SpecFactory_ReportDefinitionWarning, getSpec().getName(), source), e);

+        }

+

+        @Override

+        public void error(SAXParseException e)

+        {

+            // Just log the error

+            Logger.getLogger(getClass().getName()).log(Level.WARNING, MessageUtil.format(Messages.SpecFactory_ReportDefinitionError, getSpec().getName(), source), e);

+        }

+

+        @Override

+        public void fatalError(SAXParseException e)

+        {

+            // Just log the fatal error - an exception will be thrown later

+            Logger.getLogger(getClass().getName()).log(Level.SEVERE, MessageUtil.format(Messages.SpecFactory_ReportDefinitionSevereError, getSpec().getName(), source), e);

+        }

+

+        @Override

         public void characters(char[] ch, int start, int length) throws SAXException

         {

             if (buf != null)

@@ -310,7 +344,10 @@
 

         public Spec getSpec()

         {

-            return ((SectionSpec) stack.getFirst()).getChildren().get(0);

+            List<Spec>children = ((SectionSpec) stack.getFirst()).getChildren();

+            if (children.isEmpty())

+                return stack.getFirst();

+            return children.get(0);

         }

     }

 }

diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/Messages.java b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/Messages.java
index 155dab3..58c975e 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/Messages.java
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/Messages.java
@@ -1,5 +1,5 @@
 /*******************************************************************************

- * Copyright (c) 2008, 2021 SAP AG and IBM Corporation.

+ * Copyright (c) 2008, 2023 SAP AG and IBM Corporation.

  * All rights reserved. This program and the accompanying materials

  * are made available under the terms of the Eclipse Public License 2.0

  * which accompanies this distribution, and is available at

@@ -117,6 +117,10 @@
     public static String ResultRenderer_Label_TableOfContents;

     public static String RunRegisterdReport_Error_UnknownReport;

     public static String SpecFactory_Error_MissingTemplate;

+    public static String SpecFactory_ReportDefinitionError;

+    public static String SpecFactory_ReportDefinitionSevereError;

+    public static String SpecFactory_ReportDefinitionWarning;

+

     public static String TestSuite_FailedToUnzipReport;

     public static String TextOutputter_PieChart;

     public static String TextOutputter_Slice;

diff --git a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/messages.properties b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/messages.properties
index 815cc62..67cad5b 100644
--- a/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/messages.properties
+++ b/plugins/org.eclipse.mat.report/src/org/eclipse/mat/report/internal/messages.properties
@@ -102,6 +102,9 @@
 ResultRenderer_Label_TableOfContents=Table Of Contents

 RunRegisterdReport_Error_UnknownReport=Unknown report: {0}

 SpecFactory_Error_MissingTemplate=Template not found: {0}

+SpecFactory_ReportDefinitionError={0} report definition from ''{1}'' parse error

+SpecFactory_ReportDefinitionSevereError={0} report definition from ''{1}'' parse severe error

+SpecFactory_ReportDefinitionWarning={0} report definition from ''{1}'' parse warning

 TextOutputter_PieChart=Pie chart with {0} slices

 TextOutputter_Slice=Slice {0}: {1} {2}

 TextResult_Label_Links=Links