[SDC-380] jtosca errors cutomization

Change-Id: I18140d3f2703ff662ae4aa8c965e8137d1ad79c4
Signed-off-by: Pavel Aharoni <pa0916@att.com>
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/config/ConfigurationManager.java b/src/main/java/org/openecomp/sdc/tosca/parser/config/ConfigurationManager.java
index e83e6aa..4e09222 100644
--- a/src/main/java/org/openecomp/sdc/tosca/parser/config/ConfigurationManager.java
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/config/ConfigurationManager.java
@@ -32,6 +32,7 @@
 	private void initialConfigObjectsFromFiles() {
 		loadConfigurationClass(ErrorConfiguration.class);
 		loadConfigurationClass(Configuration.class);
+		loadConfigurationClass(JtoscaValidationIssueConfiguration.class);
 	}
 
 	private <T> void loadConfigurationClass(Class<T> clazz) {
@@ -60,13 +61,13 @@
 
 
 	public static ConfigurationManager getInstance() {
-		if (instance == null) {
-			synchronized (ConfigurationManager.class) {
-				if (instance == null) {
+	//	if (instance == null) {
+	//		synchronized (ConfigurationManager.class) {
+	//			if (instance == null) {
 					instance = new ConfigurationManager();
-				}
-			}
-		}
+	//			}
+	//		}
+	//	}
 		return instance;
 	}
 
@@ -103,6 +104,9 @@
 	public ErrorConfiguration getErrorConfiguration() {
 		return (ErrorConfiguration) configurations.get((ErrorConfiguration.class.getSimpleName()));
 	}
+	public JtoscaValidationIssueConfiguration getJtoscaValidationIssueConfiguration() {
+		return (JtoscaValidationIssueConfiguration) configurations.get((JtoscaValidationIssueConfiguration.class.getSimpleName()));
+	}
 
 	public Configuration getConfiguration() {
 		return (Configuration) configurations.get((Configuration.class.getSimpleName()));
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/config/JToscaValidationIssueInfo.java b/src/main/java/org/openecomp/sdc/tosca/parser/config/JToscaValidationIssueInfo.java
new file mode 100644
index 0000000..31ab0a0
--- /dev/null
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/config/JToscaValidationIssueInfo.java
@@ -0,0 +1,31 @@
+package org.openecomp.sdc.tosca.parser.config;
+
+public class JToscaValidationIssueInfo {
+
+    private String issueType;
+    private String sinceCsarConformanceLevel;
+
+    public JToscaValidationIssueInfo() {}
+
+    public String getIssueType() {
+        return issueType;
+    }
+
+    public void setIssueType(String issueType) {
+        this.issueType = issueType;
+    }
+
+    public String getSinceCsarConformanceLevel() {
+        return sinceCsarConformanceLevel;
+    }
+
+    public void setSinceCsarConformanceLevel(String sinceCsarConformanceLevel) {
+        this.sinceCsarConformanceLevel = sinceCsarConformanceLevel;
+    }
+
+    public void cloneData(JToscaValidationIssueInfo other) {
+        this.issueType = other.getIssueType();
+        this.sinceCsarConformanceLevel = other.getSinceCsarConformanceLevel();
+    }
+
+}
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/config/JtoscaValidationIssueConfiguration.java b/src/main/java/org/openecomp/sdc/tosca/parser/config/JtoscaValidationIssueConfiguration.java
new file mode 100644
index 0000000..ff13251
--- /dev/null
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/config/JtoscaValidationIssueConfiguration.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.tosca.parser.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class JtoscaValidationIssueConfiguration {
+
+    private Map<String, List<JToscaValidationIssueInfo>> validationIssues;
+
+    public Map<String, List<JToscaValidationIssueInfo>> getValidationIssues() {
+		return validationIssues;
+	}
+
+	public void setValidationIssues(Map<String, List<JToscaValidationIssueInfo>> validationIssues) {
+		this.validationIssues = validationIssues;
+	}
+	
+	public List<JToscaValidationIssueInfo> getJtoscaValidationIssueInfo(String key) {
+        List<JToscaValidationIssueInfo> clone = new ArrayList<>();
+        List<JToscaValidationIssueInfo> other = validationIssues.get(key);
+        if (other != null) {
+            for (JToscaValidationIssueInfo item: other) {
+                JToscaValidationIssueInfo cloneitem = new JToscaValidationIssueInfo();
+                cloneitem.cloneData(item);
+                clone.add(cloneitem);
+            }
+        }
+        return clone;
+    }
+
+}
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/impl/JToscaValidationIssueType.java b/src/main/java/org/openecomp/sdc/tosca/parser/impl/JToscaValidationIssueType.java
new file mode 100644
index 0000000..1e68c51
--- /dev/null
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/impl/JToscaValidationIssueType.java
@@ -0,0 +1,6 @@
+package org.openecomp.sdc.tosca.parser.impl;
+
+public enum JToscaValidationIssueType {
+	CRITICAL,
+	WARNING
+}
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/impl/SdcToscaParserFactory.java b/src/main/java/org/openecomp/sdc/tosca/parser/impl/SdcToscaParserFactory.java
index 868b84f..c9cac1c 100644
--- a/src/main/java/org/openecomp/sdc/tosca/parser/impl/SdcToscaParserFactory.java
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/impl/SdcToscaParserFactory.java
@@ -1,20 +1,31 @@
 package org.openecomp.sdc.tosca.parser.impl;

 

+import java.util.ArrayList;

+import java.util.List;

+

 import org.openecomp.sdc.tosca.parser.api.ConformanceLevel;

 import org.openecomp.sdc.tosca.parser.api.ISdcCsarHelper;

 import org.openecomp.sdc.tosca.parser.config.*;

 import org.openecomp.sdc.tosca.parser.exceptions.SdcToscaParserException;

 import org.openecomp.sdc.tosca.parser.utils.GeneralUtility;

 import org.openecomp.sdc.toscaparser.api.ToscaTemplate;

+import org.openecomp.sdc.toscaparser.api.common.JToscaValidationIssue;

 import org.openecomp.sdc.toscaparser.api.common.JToscaException;

 import org.openecomp.sdc.toscaparser.api.utils.JToscaErrorCodes;

+import org.openecomp.sdc.toscaparser.api.utils.ThreadLocalsHolder;

+import org.slf4j.Logger;

+import org.slf4j.LoggerFactory;

 

 public class SdcToscaParserFactory {

-

+	private static Logger log = LoggerFactory.getLogger(SdcToscaParserFactory.class.getName());

+	

     private static volatile SdcToscaParserFactory instance;

     private static Configuration configuration;

     private static ErrorConfiguration errorConfiguration;

-

+    private static JtoscaValidationIssueConfiguration jtoscaValidationIssueConfiguration;

+    private List<JToscaValidationIssue> criticalExceptions = new ArrayList<>();

+    private List<JToscaValidationIssue> warningExceptions = new ArrayList<>();

+    private List<JToscaValidationIssue> notAnalyzadExceptions = new ArrayList<>();

     private SdcToscaParserFactory() {

 

     }

@@ -30,6 +41,7 @@
                     instance = new SdcToscaParserFactory();

                     configuration = ConfigurationManager.getInstance().getConfiguration();

                     errorConfiguration = ConfigurationManager.getInstance().getErrorConfiguration();

+                    jtoscaValidationIssueConfiguration = ConfigurationManager.getInstance().getJtoscaValidationIssueConfiguration();

                 }

             }

         }

@@ -68,12 +80,93 @@
                 throwSdcToscaParserException(e);

             }

             SdcCsarHelperImpl sdcCsarHelperImpl = new SdcCsarHelperImpl(tosca);

-            validateCsarVersion(sdcCsarHelperImpl.getConformanceLevel());

+            String cSarConformanceLevel = sdcCsarHelperImpl.getConformanceLevel();

+            validateCsarVersion(cSarConformanceLevel);

+            try {

+                handleErrorsByTypes(csarPath, cSarConformanceLevel);

+			} catch (JToscaException e) {

+				// TODO Auto-generated catch block

+				e.printStackTrace();

+			}

             return sdcCsarHelperImpl;

         }

     }

 

-    private void validateCsarVersion(String cSarVersion) throws SdcToscaParserException {

+    private void handleErrorsByTypes(String csarPath, String cSarConformanceLevel) throws JToscaException {

+        clearValidationIssuesLists();

+    	for(JToscaValidationIssue toscaValidationIssue : ThreadLocalsHolder.getCollector().getValidationIssues().values()){

+            List<JToscaValidationIssueInfo> issueInfos = jtoscaValidationIssueConfiguration.getValidationIssues().get(toscaValidationIssue.getCode());

+    		if(issueInfos != null && !issueInfos.isEmpty()){

+                JToscaValidationIssueInfo issueInfo = null;

+    			issueInfo = issueInfos.stream()

+                    .filter(i-> isMatchConformanceLevel(cSarConformanceLevel,i.getSinceCsarConformanceLevel()))

+                    .max((i1,i2) -> GeneralUtility.conformanceLevelCompare(i1.getSinceCsarConformanceLevel(), i2.getSinceCsarConformanceLevel()) )

+                    .orElse(null);

+

+    			if(issueInfo != null){

+                    switch (JToscaValidationIssueType.valueOf(issueInfo.getIssueType())) {

+                        case CRITICAL:

+                            criticalExceptions.add(toscaValidationIssue);

+                            break;

+                        case WARNING:

+                            warningExceptions.add(toscaValidationIssue);

+                            break;

+                        default:

+                            break;

+                    }

+                }else{

+                    notAnalyzadExceptions.add(toscaValidationIssue);

+                }

+            }else{//notAnalyzed

+                notAnalyzadExceptions.add(toscaValidationIssue);

+            }

+    	}

+    	logErrors(csarPath);

+    }

+

+    private void clearValidationIssuesLists(){

+        notAnalyzadExceptions.clear();

+        criticalExceptions.clear();

+        warningExceptions.clear();

+    }

+

+    private void logErrors(String inputPath) throws JToscaException{

+		//Warnings

+		int warningsCount = warningExceptions.size();

+		if (warningsCount > 0) {

+			log.warn("####################################################################################################");

+			log.warn("CSAR Warnings found! CSAR name - {}", inputPath);

+			log.warn("ToscaTemplate - verifyTemplate - {} Parsing Warning{} occurred...", warningsCount, (warningsCount > 1 ? "s" : ""));

+			for (JToscaValidationIssue info : warningExceptions) {

+				log.warn("JTosca Exception [{}]: {}. CSAR name - {}", info.getCode(),info.getMessage(), inputPath);

+			}

+			log.warn("####################################################################################################");

+		}

+		//Criticals

+		int criticalsCount = criticalExceptions.size();

+		if (criticalsCount > 0) {

+			log.error("####################################################################################################");

+			log.error("ToscaTemplate - verifyTemplate - {} Parsing Critical{} occurred...", criticalsCount, (criticalsCount > 1 ? "s" : ""));

+			for (JToscaValidationIssue info : criticalExceptions) {

+				log.error("JTosca Exception [{}]: {}. CSAR name - {}", info.getCode(),info.getMessage(), inputPath);

+			}

+			throw new JToscaException(String.format("CSAR Validation Failed. CSAR name - {}. Please check logs for details.", inputPath), JToscaErrorCodes.CSAR_TOSCA_VALIDATION_ERROR.getValue());

+		}

+    }

+    public List<JToscaValidationIssue> getCriticalExceptions() {

+		return criticalExceptions;

+	}

+

+	public List<JToscaValidationIssue> getWarningExceptions() {

+		return warningExceptions;

+	}

+

+	public List<JToscaValidationIssue> getNotAnalyzadExceptions() {

+		return notAnalyzadExceptions;

+	}

+

+

+	private void validateCsarVersion(String cSarVersion) throws SdcToscaParserException {

         ConformanceLevel level = configuration.getConformanceLevel();

         String minVersion = level.getMinVersion();

         String maxVersion = level.getMaxVersion();

@@ -86,6 +179,14 @@
         }

     }

 

+    private boolean isMatchConformanceLevel(String ValidationIssueVersion, String cSarVersion){

+        if (ValidationIssueVersion != null && cSarVersion != null) {

+            if ((GeneralUtility.conformanceLevelCompare(ValidationIssueVersion, cSarVersion) >= 0)) {

+                return true;

+            }

+        }

+        return false;

+    }

     private void throwConformanceLevelException(String minVersion, String maxVersion) throws SdcToscaParserException {

         ErrorInfo errorInfo = errorConfiguration.getErrorInfo(SdcToscaParserErrors.CONFORMANCE_LEVEL_ERROR.toString());

         throw new SdcToscaParserException(String.format(errorInfo.getMessage(), minVersion, maxVersion), errorInfo.getCode());

@@ -95,4 +196,5 @@
         ErrorInfo errorInfo = errorConfiguration.getErrorInfo(SdcToscaParserErrors.getSdcErrorByJToscaError(JToscaErrorCodes.getByCode(e.getCode())).toString());

         throw new SdcToscaParserException(errorInfo.getMessage(), errorInfo.getCode());

     }

+

 }
\ No newline at end of file
diff --git a/src/main/java/org/openecomp/sdc/tosca/parser/utils/YamlToObjectConverter.java b/src/main/java/org/openecomp/sdc/tosca/parser/utils/YamlToObjectConverter.java
index 44444d2..926b155 100644
--- a/src/main/java/org/openecomp/sdc/tosca/parser/utils/YamlToObjectConverter.java
+++ b/src/main/java/org/openecomp/sdc/tosca/parser/utils/YamlToObjectConverter.java
@@ -20,6 +20,7 @@
 
 package org.openecomp.sdc.tosca.parser.utils;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
@@ -109,11 +110,13 @@
 	public <T> T convertFromString(String yamlContents, Class<T> className) {
 
 		T config = null;
-
-		Yaml yaml = getYamlByClassName(className);
-
+		Yaml yaml = new Yaml();
 		try {
-			config = yaml.loadAs(yamlContents, className);
+			Object data = yaml.load(yamlContents);
+            // convert it manually with jackson instead of using snakeyaml auto converter,
+            // because of problematic complex objects like JtoscaValidationIssueConfiguration
+			ObjectMapper mapper = new ObjectMapper(); 
+			config = mapper.convertValue(data, className);
 		} catch (Exception e){
 			log.error("Failed to convert YAML {} to object." , yamlContents, e);
 		}
diff --git a/src/main/resources/config/jtosca-validation-issue-configuration.yaml b/src/main/resources/config/jtosca-validation-issue-configuration.yaml
new file mode 100644
index 0000000..f4bb949
--- /dev/null
+++ b/src/main/resources/config/jtosca-validation-issue-configuration.yaml
@@ -0,0 +1,49 @@
+# jTosca validation issues 
+#by error code, type the validation issue to be CRITICAL/WARNING 
+# since Conformance level considered to this type. for example:
+#JE001: 
+#      - issueType: WARNING
+#        sinceCsarConformanceLevel: 3.0     
+#      - issueType: WARNING
+#        sinceCsarConformanceLevel: 5.0
+validationIssues:
+    # TypeMismatchError
+    JE001: 
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    # MissingType
+    JE002:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #MissingRequiredFieldError
+    JE003:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #MissingRequiredFieldError2
+    JE004:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #InvalidGroupTargetException
+    JE005:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #Schema definition of \"%s\" has \"status\" attribute with an invalid value
+    JE006:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #The unit \"%s\" is not valid
+    JE007:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #ValidationError
+    JE008:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #ValueError: Expected max 2 arguments for function \"get_input\" but received \"%s\"",args.size())
+    JE009:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #MissingRequiredFieldError3
+    JE010:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
\ No newline at end of file
diff --git a/src/test/java/org/openecomp/sdc/impl/ToscaParserValidationIssueTest.java b/src/test/java/org/openecomp/sdc/impl/ToscaParserValidationIssueTest.java
new file mode 100644
index 0000000..72bb5df
--- /dev/null
+++ b/src/test/java/org/openecomp/sdc/impl/ToscaParserValidationIssueTest.java
@@ -0,0 +1,60 @@
+package org.openecomp.sdc.impl;
+
+import static org.testng.Assert.assertEquals;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.openecomp.sdc.tosca.parser.api.ISdcCsarHelper;
+import org.openecomp.sdc.tosca.parser.exceptions.SdcToscaParserException;
+import org.openecomp.sdc.toscaparser.api.common.JToscaValidationIssue;
+import org.testng.annotations.Test;
+
+public class ToscaParserValidationIssueTest extends SdcToscaParserBasicTest {
+
+	@Test
+	public void testNoValidationIssues() throws SdcToscaParserException {
+		ISdcCsarHelper rainyCsarHelper = getCsarHelper("csars/service-ServiceFdnt-csar-rainy.csar");//conformance level 3.0
+
+		//List<JToscaValidationIssue> notAnalyzedReport = factory.getNotAnalyzadExceptions();
+		//assertEquals( notAnalyzedReport.size(),0);
+		List<JToscaValidationIssue> warningsReport = factory.getWarningExceptions();
+		assertEquals( warningsReport.size(),0);
+		List<JToscaValidationIssue> criticalsReport = factory.getCriticalExceptions();
+		assertEquals( criticalsReport.size(),0);
+	}
+	@Test
+	public void testGetLowSinceConformanceLevel() throws SdcToscaParserException {
+		ISdcCsarHelper fdntCsarHelperWithInputs = getCsarHelper("csars/service-NfodService-csar.csar");//conformance level 3.0
+		//Service level
+
+		List<JToscaValidationIssue> notAnalyzedReport = factory.getNotAnalyzadExceptions();
+		assertEquals( notAnalyzedReport.size(),10);
+		//JE003 high CL 4.0
+		assertEquals( notAnalyzedReport.stream().filter(n->n.getCode().equals("JE003")).collect(Collectors.toList()).size(), 2);
+		assertEquals( notAnalyzedReport.stream().filter(n->n.getCode().equals("JE235")).collect(Collectors.toList()).size(), 7);
+		assertEquals( notAnalyzedReport.stream().filter(n->n.getCode().equals("JE236")).collect(Collectors.toList()).size(), 1);
+		List<JToscaValidationIssue> warningsReport = factory.getWarningExceptions();
+		assertEquals( warningsReport.size(),14);
+		assertEquals( warningsReport.stream().filter(w->w.getCode().equals("JE006")).collect(Collectors.toList()).size(), 13);
+		//JE004 low CL 2.0
+		assertEquals( warningsReport.stream().filter(w->w.getCode().equals("JE004")).collect(Collectors.toList()).size(), 1);
+		List<JToscaValidationIssue> criticalsReport = factory.getCriticalExceptions();
+		assertEquals( criticalsReport.size(),0);
+	}
+	@Test
+	public void testMultiSinceConformanceLevelIssues() throws SdcToscaParserException {
+		ISdcCsarHelper Nfod2images = getCsarHelper("csars/service-Nfod2images-csar.csar");//conformance level 4.0
+		List<JToscaValidationIssue> notAnalyzedReport = factory.getNotAnalyzadExceptions();
+		assertEquals( notAnalyzedReport.size(),17);
+		List<JToscaValidationIssue> warningsReport = factory.getWarningExceptions();
+		assertEquals( warningsReport.size(),0);
+		List<JToscaValidationIssue> criticalsReport = factory.getCriticalExceptions();
+		assertEquals( criticalsReport.size(),24);
+		//JE006 multy values sinceCsarConformanceLevel
+		assertEquals( criticalsReport.stream().filter(c->c.getCode().equals("JE006")).collect(Collectors.toList()).size(), 18);
+		assertEquals( criticalsReport.stream().filter(c->c.getCode().equals("JE003")).collect(Collectors.toList()).size(), 6);
+	}
+
+
+}
diff --git a/src/test/resources/config/jtosca-validation-issue-configuration.yaml b/src/test/resources/config/jtosca-validation-issue-configuration.yaml
new file mode 100644
index 0000000..1378ca7
--- /dev/null
+++ b/src/test/resources/config/jtosca-validation-issue-configuration.yaml
@@ -0,0 +1,57 @@
+# jTosca validation issues
+#by error code, type the validation issue to be CRITICAL/WARNING
+# since Conformance level considered to this type. for example:
+#JE001:
+#      - type: WARNING,
+#        sinceCsarConformanceLevel: 3.0
+#      - type: WARNING,
+#        sinceCsarConformanceLevel: 5.0
+validationIssues:
+    # TypeMismatchError
+    JE001:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+        - issueType: CRITICAL
+          sinceCsarConformanceLevel: 4.0
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 5.0
+    # MissingType
+    JE002:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #MissingRequiredFieldError
+    JE003:
+        - issueType: CRITICAL
+          sinceCsarConformanceLevel: 4.0
+    #MissingRequiredFieldError2
+    JE004:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 2.0
+    #InvalidGroupTargetException
+    JE005:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #Schema definition of \"%s\" has \"status\" attribute with an invalid value
+    JE006:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+        - issueType: CRITICAL
+          sinceCsarConformanceLevel: 4.0
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 5.0
+    #The unit \"%s\" is not valid
+    JE007:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #ValidationError
+    JE008:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #ValueError: Expected max 2 arguments for function \"get_input\" but received \"%s\"",args.size())
+    JE009:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
+    #MissingRequiredFieldError3
+    JE010:
+        - issueType: WARNING
+          sinceCsarConformanceLevel: 3.0
\ No newline at end of file