Merge "Guard Policy documentation"
diff --git a/POLICY-SDK-APP/src/main/java/org/onap/policy/controller/CreateDcaeMicroServiceController.java b/POLICY-SDK-APP/src/main/java/org/onap/policy/controller/CreateDcaeMicroServiceController.java
index 0f55ba6..ff5ccff 100644
--- a/POLICY-SDK-APP/src/main/java/org/onap/policy/controller/CreateDcaeMicroServiceController.java
+++ b/POLICY-SDK-APP/src/main/java/org/onap/policy/controller/CreateDcaeMicroServiceController.java
@@ -175,6 +175,7 @@
 			
 			//---replace empty value with the value below before calling decodeContent method.
 			String dummyValue = "*empty-value*" + UUID.randomUUID().toString();
+			LOGGER.info("dummyValue:" + dummyValue);
 			tempJson = StringUtils.replaceEach(tempJson, new String[]{"\"\""}, new String[]{"\""+dummyValue+"\""});
 			ObjectMapper mapper = new ObjectMapper();
 			JsonNode tempJsonNode = mapper.readTree(tempJson);
@@ -274,13 +275,21 @@
 				final JsonNode value = field.getValue();
 				if("content".equalsIgnoreCase(key)){
 					String contentStr = value.toString();
-				    try (JsonReader jsonReader = Json.createReader(new StringReader(contentStr))) {		
-				    	JsonObject jsonContent = jsonReader.readObject();
-					    removed = removeNull(jsonContent);
-					    if(!jsonContent.toString().equals(removed.toString())){
-					    	contentChanged = true;	
-					    }
-				    }
+					try(JsonReader reader = Json.createReader(new StringReader(contentStr))){
+	                        JsonObject jsonContent = reader.readObject();                 
+							removed = removeNull(jsonContent);
+							if(!jsonContent.toString().equals(removed.toString())){
+							contentChanged = true;  
+						}
+                    }
+
+					if  (value==null || value.isNull()){
+						((ObjectNode) returnNode).remove(key);
+						remove = true;
+					}
+				}
+				if (remove){
+					cleanJson = returnNode.toString();
 				}
 				if  (value==null || value.isNull()){
 					((ObjectNode) returnNode).remove(key);
@@ -412,8 +421,13 @@
 		}
 
 		Yaml yaml = new Yaml();
-		@SuppressWarnings("unchecked")
-		Map<Object, Object> yamlMap = (Map<Object, Object>) yaml.load(is); 
+
+		Map<Object, Object> yamlMap = null;
+		try{
+		    yamlMap = (Map<Object, Object>) yaml.load(is); 
+		}catch(Exception e){
+			LOGGER.error("load:", e);
+		}
 		StringBuilder sb = new StringBuilder(); 
 		Map<String, String> settings = new HashMap<>(); 
 		if (yamlMap == null) { 
@@ -517,7 +531,7 @@
 				String findType=DATATYPE+uniqueDataKeySplit[0]+PROPERTIES+uniqueDataKeySplit[1]+TYPE;
 				String typeValue=map.get(findType);
 				LOGGER.info(typeValue);
-				if(typeValue.equalsIgnoreCase(STRING)||
+				if(typeValue != null && typeValue.equalsIgnoreCase(STRING)||
 						typeValue.equalsIgnoreCase(INTEGER)
 				  )
 				{
@@ -535,7 +549,7 @@
 					attributeIndividualStringBuilder.append(requiredValue+MANYFALSE);
 					dataMapForJson.put(uniqueDataKey, attributeIndividualStringBuilder.toString());		
 				}
-				else if(typeValue.equalsIgnoreCase(LIST)){
+				else if(typeValue != null && typeValue.equalsIgnoreCase(LIST)){
 					String findList= DATATYPE+uniqueDataKeySplit[0]+PROPERTIES+uniqueDataKeySplit[1]+".entry_schema.type";
 					String listValue=map.get(findList);
 					if(listValue!=null){
@@ -677,8 +691,8 @@
 		for(Map.Entry<String,HashMap<String,String>> entry: mapKey.entrySet()){
 			String keySetString= entry.getKey();
 			HashMap<String,String> keyValues=mapKey.get(keySetString);
-			if(keyValues.get("type").equalsIgnoreCase(STRING)||
-					keyValues.get("type").equalsIgnoreCase(INTEGER)
+			if(keyValues.get("type") != null && keyValues.get("type").equalsIgnoreCase(STRING)||
+					keyValues.get("type") != null && keyValues.get("type").equalsIgnoreCase(INTEGER)
 					){
 				StringBuilder attributeIndividualStringBuilder= new StringBuilder();
 				attributeIndividualStringBuilder.append(keySetString+"=");
@@ -688,7 +702,7 @@
 				attributeStringBuilder.append(attributeIndividualStringBuilder+",");	
 
 			}
-			else if(keyValues.get("type").equalsIgnoreCase(LIST)){
+			else if(keyValues.get("type") != null && keyValues.get("type").equalsIgnoreCase(LIST)){
 				//List Datatype
 				Set<String> keys= keyValues.keySet();
 				Iterator<String> itr=keys.iterator();
@@ -714,10 +728,14 @@
 			}else{
 				//User defined Datatype. 
 				String value=keyValues.get("type");
-				String trimValue=value.substring(value.lastIndexOf('.')+1);
-				StringBuilder referenceIndividualStringBuilder= new StringBuilder();
-				referenceIndividualStringBuilder.append(keySetString+"="+trimValue+":MANY-false");
-				referenceStringBuilder.append(referenceIndividualStringBuilder+",");
+				if(value != null && !value.isEmpty()){
+					String trimValue=value.substring(value.lastIndexOf('.')+1);
+					StringBuilder referenceIndividualStringBuilder= new StringBuilder();
+					referenceIndividualStringBuilder.append(keySetString+"="+trimValue+":MANY-false");
+					referenceStringBuilder.append(referenceIndividualStringBuilder+",");
+				}else{
+					LOGGER.info("keyValues.get(type) is null/empty");
+				}
 
 			}
 			if(constraints!=null &&constraints.isEmpty()==false){
@@ -953,7 +971,7 @@
 				}
 				jsonArray.put(decodeContent(node));
 				jsonResult.put(arryKey, jsonArray);
-				isArray = false;;
+				isArray = false;
 			}else{
 				jsonResult.put(nodeKey, decodeContent(node));
 			}
@@ -978,7 +996,53 @@
 		}
 		MicroServiceModels returnModel = getAttributeObject(servicename, version);
 		
-		String jsonModel = createMicroSeriveJson(returnModel);
+		
+		//get all keys with "MANY-true" defined in their value from subAttribute
+		Set<String> allkeys = null;
+		if(returnModel.getSub_attributes() != null && !returnModel.getSub_attributes().isEmpty()){
+			JSONObject json = new JSONObject(returnModel.getSub_attributes());		
+			allkeys = getAllKeys(json);
+			LOGGER.info("allkeys : " + allkeys);
+		}
+		
+		String allManyTrueKeys = "";
+		if(allkeys != null){
+			allManyTrueKeys = allkeys.toString();
+		}
+		
+		String jsonModel = createMicroSeriveJson(returnModel, allkeys);
+		
+		JSONObject jsonObject = new JSONObject(jsonModel);
+		
+		JSONObject finalJsonObject = null;
+		if(allkeys != null){
+			Iterator<String> iter = allkeys.iterator();
+			while(iter.hasNext()){
+				//convert to array values for MANY-true keys
+				finalJsonObject = convertToArrayElement(jsonObject, iter.next());
+			}
+		}
+
+		if(finalJsonObject != null){
+		    LOGGER.info(finalJsonObject.toString());
+		    jsonModel  = finalJsonObject.toString();
+		}
+		
+		//get all properties with "MANY-true" defined in Ref_attributes
+		Set<String> manyTrueProperties = getManyTrueProperties(returnModel.getRef_attributes());
+		if(manyTrueProperties != null){
+			JSONObject jsonObj = new JSONObject(jsonModel);
+			for (String s : manyTrueProperties) {
+				LOGGER.info(s);
+				//convert to array element for MANY-true properties
+				finalJsonObject = convertToArrayElement(jsonObj, s.trim());
+			}
+			
+			if(finalJsonObject != null){
+			    LOGGER.info(finalJsonObject.toString());
+			    jsonModel  = finalJsonObject.toString();
+			}
+		}
 		
 		response.setCharacterEncoding("UTF-8");
 		response.setContentType("application / json");
@@ -986,14 +1050,14 @@
 		List<Object>  list = new ArrayList<>();
 		PrintWriter out = response.getWriter();
 		String responseString = mapper.writeValueAsString(returnModel);
-		JSONObject j = new JSONObject("{dcaeModelData: " + responseString + ",jsonValue: " + jsonModel + "}");
+		JSONObject j = new JSONObject("{dcaeModelData: " + responseString + ",jsonValue: " + jsonModel + ",allManyTrueKeys: " + allManyTrueKeys+ "}");
 		list.add(j);
 		out.write(list.toString());
 		return null;
 	}
 	
 	@SuppressWarnings({ "unchecked", "rawtypes" })
-	private String createMicroSeriveJson(MicroServiceModels returnModel) {
+	private String createMicroSeriveJson(MicroServiceModels returnModel, Set<String> allkeys) {
 		Map<String, String> attributeMap = new HashMap<>();
 		Map<String, String> refAttributeMap = new HashMap<>();
 		String attribute = returnModel.getAttributes();
@@ -1058,6 +1122,8 @@
 				}
 			}
 		}
+		
+		
 
 		return object.toString();
 	}
@@ -1092,6 +1158,101 @@
 		
 		return object;
 	}
+	
+	//call this method to check if the key is in the many-true key set 
+	private boolean isKeyFound(Set<String> allManyTruekeys, String key){
+		
+	     if(allManyTruekeys != null && key != null){
+	    	Iterator<String> iter = allManyTruekeys.iterator();
+	    	while(iter.hasNext()){
+	    		if(key.equals(iter.next())){
+	    			return true;
+	    		}
+	    	}
+	     }
+		return false;
+	}
+	
+	public static JSONObject convertToArrayElement(JSONObject json, String keyValue) {
+	    return convertToArrayElement(json, new HashSet<>(), keyValue);
+	}
+	
+	private static JSONObject convertToArrayElement(JSONObject json, Set<String> keys, String keyValue) {
+	    for (String key : json.keySet()) {
+	        Object obj = json.get(key);
+	        if(key.equals(keyValue.trim())){
+	        	if(!(obj instanceof JSONArray)){
+	        		JSONArray newJsonArray = new JSONArray();
+	        		newJsonArray.put(obj);
+	        		json.put(key, newJsonArray);
+	        	}
+	        	LOGGER.info("key : " + key);
+	        	LOGGER.info("obj : " + obj);
+	        	LOGGER.info("json.get(key) : " + json.get(key));
+	        	LOGGER.info("keyValue : " + keyValue);
+	    	    keys.addAll(json.keySet());
+	    	    
+	    	    return json;
+	        }
+
+	        if (obj instanceof JSONObject) convertToArrayElement(json.getJSONObject(key), keyValue);	    
+	    }
+
+	    return json;
+	}
+	
+	// call this method to get all MANY-true properties 
+	public static Set<String> getManyTrueProperties(String referAttributes){
+		LOGGER.info("referAttributes : " + referAttributes);
+		Set<String> manyTrueProperties = new HashSet<>();
+		
+		if(referAttributes != null){
+			String[] referAarray = referAttributes.split(",");
+			String []element= null;
+			for(int i=0; i<referAarray.length; i++){
+				element = referAarray[i].split("=");	  
+				if(element.length > 1 && element[1].contains("MANY-true")){
+					manyTrueProperties.add(element[0]);
+				}
+			}		
+		}
+		
+		return manyTrueProperties;
+	}
+	
+	//call this method to start the recursive
+	private Set<String> getAllKeys(JSONObject json) {
+	    return getAllKeys(json, new HashSet<>());
+	}
+
+	private Set<String> getAllKeys(JSONArray arr) {
+	    return getAllKeys(arr, new HashSet<>());
+	}
+
+	private Set<String> getAllKeys(JSONArray arr, Set<String> keys) {
+	    for (int i = 0; i < arr.length(); i++) {
+	        Object obj = arr.get(i);
+	        if (obj instanceof JSONObject) keys.addAll(getAllKeys(arr.getJSONObject(i)));
+	        if (obj instanceof JSONArray) keys.addAll(getAllKeys(arr.getJSONArray(i)));
+	    }
+
+	    return keys;
+	}
+    // this method returns a set of keys with "MANY-true" defined in their value.
+	private Set<String> getAllKeys(JSONObject json, Set<String> keys) {
+	    for (String key : json.keySet()) {
+	        Object obj = json.get(key);
+	        if(obj instanceof String && ((String) obj).contains("MANY-true")){
+	        	LOGGER.info("key : " + key);
+	        	LOGGER.info("obj : " + obj);
+	    	    keys.addAll(json.keySet());
+	        }
+	        if (obj instanceof JSONObject) keys.addAll(getAllKeys(json.getJSONObject(key)));
+	        if (obj instanceof JSONArray) keys.addAll(getAllKeys(json.getJSONArray(key)));
+	    }
+
+	    return keys;
+	}
 
 	
 	@RequestMapping(value={"/policyController/getModelServiceVersioneData.htm"}, method={org.springframework.web.bind.annotation.RequestMethod.POST})
@@ -1379,9 +1540,18 @@
 	
 	@RequestMapping(value={"/ms_dictionary/set_MSModelData"}, method={org.springframework.web.bind.annotation.RequestMethod.POST})
 	public void SetMSModelData(HttpServletRequest request, HttpServletResponse response) throws IOException, FileUploadException{
+		modelList = new ArrayList<>();
+		dirDependencyList = new ArrayList<>();
+		classMap = new HashMap<>();
+		retmap = new HashMap<>();
+		uniqueKeys= new HashSet<>();
+		uniqueDataKeys= new HashSet<>();
+		dataListBuffer=new StringBuilder();
+		dataConstraints= new ArrayList <>();
 		List<FileItem> items = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
 		boolean zip = false;
 		boolean yml= false;
+		String errorMsg = "";
 		for (FileItem item : items) {
 			if(item.getName().endsWith(".zip") || item.getName().endsWith(".xmi")||item.getName().endsWith(".yml")){
 				this.newModel = new MicroServiceModels();
@@ -1404,14 +1574,33 @@
 						else {
 							this.newModel.setVersion(this.newFile.toString().split("-v")[1].replace(".xmi", ""));
 						}
+					}else{
+						errorMsg = "Upload error: The file name should contain '-v', such as xxx-v1802.yml";
 					}
 				
 				}catch(Exception e){
-					LOGGER.error("Upload error : " + e);
+					LOGGER.error("Upload error : ", e);
+					errorMsg = "Upload error:" + e.getMessage();
 				}
 			}
 			
 		}
+		
+		if(!errorMsg.isEmpty()){
+			
+			PrintWriter out = response.getWriter();
+			
+			response.setCharacterEncoding("UTF-8");
+			response.setContentType("application / json");
+			request.setCharacterEncoding("UTF-8");
+			
+			ObjectMapper mapper = new ObjectMapper();
+			JSONObject j = new JSONObject();
+			j.put("errorMsg", errorMsg);
+			out.write(j.toString());
+			return;
+		}
+		
 		List<File> fileList = new ArrayList<>();;
 		this.directory = "model";
 		if (zip){
diff --git a/POLICY-SDK-APP/src/main/webapp/app/policyApp/controller/dictionaryController/MSModelsDictController.js b/POLICY-SDK-APP/src/main/webapp/app/policyApp/controller/dictionaryController/MSModelsDictController.js
index a010044..105225a 100644
--- a/POLICY-SDK-APP/src/main/webapp/app/policyApp/controller/dictionaryController/MSModelsDictController.js
+++ b/POLICY-SDK-APP/src/main/webapp/app/policyApp/controller/dictionaryController/MSModelsDictController.js
@@ -46,6 +46,11 @@
     			headers: {'Content-Type': undefined },
     			transformRequest: angular.identity
     		}).success(function(data){
+    			if(data.errorMsg != undefined){
+    				Notification.error(data.errorMsg);
+    				valid = false;
+    				return;
+    			}     			
                 if(data.classListDatas  == "EMPTY"){
                 	Notification.error("No Micro Services Avaialble.")
                 }else{      
diff --git a/POLICY-SDK-APP/src/main/webapp/app/policyApp/policy-models/Editor/PolicyTemplateController/DCAEMicroServicePolicyController.js b/POLICY-SDK-APP/src/main/webapp/app/policyApp/policy-models/Editor/PolicyTemplateController/DCAEMicroServicePolicyController.js
index 663d884..5ae453a 100644
--- a/POLICY-SDK-APP/src/main/webapp/app/policyApp/policy-models/Editor/PolicyTemplateController/DCAEMicroServicePolicyController.js
+++ b/POLICY-SDK-APP/src/main/webapp/app/policyApp/policy-models/Editor/PolicyTemplateController/DCAEMicroServicePolicyController.js
@@ -219,7 +219,6 @@
 								plainAttributeKeys.push(inputs[i].id);
 							}
 						} else {
-//							removeValues.push(inputs[i].id);
 							plainAttributeKeys.push(inputs[i].id);
 						}
 					}else {
@@ -258,6 +257,12 @@
 	 $scope.removeChoice = function(value) {
 		 console.log(value);
 		 if(value != undefined){
+			 var c = document.getElementById("div."+value).childElementCount;
+			 
+			 if(c == 1){
+				 Notification.error("The original one is not removable.");
+				 return;
+			 }	
 			 document.getElementById("div."+value).removeChild(document.getElementById("div."+value).lastChild);	 
 		 }
 	 };
@@ -315,12 +320,14 @@
                     	var plainAttributeKeys = [];
                     	$scope.dcaeModelData = data[0].dcaeModelData;
                     	$scope.dcaeJsonDate = data[0].jsonValue;
+                    	$scope.allManyTrueKeys =  data[0].allManyTrueKeys;
+                    	console.log("$scope.allManyTrueKeys: " + $scope.allManyTrueKeys);
                     	console.log("$scope.dcaeJsonDate: " + $scope.dcaeJsonDate);	
                     	var attributes = $scope.dcaeModelData.attributes;
                     	var refAttributes = $scope.dcaeModelData.ref_attributes;
                     	var subAttributes = 	$scope.dcaeModelData.sub_attributes;                    	
                     	console.log("subAttributes: " + subAttributes);	
-                    	
+                    	console.log("refAttributes: " + refAttributes);	
                        	var enumAttributes = $scope.dcaeModelData.enumValues;
                        	var annotation = $scope.dcaeModelData.annotation;
                        	var dictionary = $scope.microServiceAttributeDictionaryDatas;
@@ -363,29 +370,45 @@
                 		$scope.jsonLayout($scope.dcaeJsonDate);
                 		
                     });
+                    
                     if($scope.temp.policy.editPolicy || $scope.temp.policy.readOnly){
                     	var checkData = [];
                     	var data = [];
-                    	if($scope.temp.policy.ruleData != null){
-                    		var propNames = Object.getOwnPropertyNames($scope.temp.policy.ruleData);
-                    		propNames.forEach(function(name) {
-                    			data.push(name);
-                    		});
-                    		for(a = 0; a < data.length; a++){
-                    			var splitPlainAttributeKey1 = data[a].split(".");
-                    			if(splitPlainAttributeKey1[0].indexOf("@") != -1){
-                    				var key = splitPlainAttributeKey1[0];
-                        			checkData.push(key);
-                    			}
-                    		}
-                    		var unique = checkData.filter(onlyUnique);
-                    		for(i =0; i < unique.length; i++){
-                    			if(unique[i].indexOf("@0") == -1){
-                    				var finalkey = unique[i].split("@")[0];
-                    				$scope.addNewChoice(finalkey);
-                    			}	
-                    		}
-                    	}
+	                    	if($scope.temp.policy.ruleData != null){
+	                    		var propNames = Object.getOwnPropertyNames($scope.temp.policy.ruleData);
+	                    		propNames.forEach(function(name) {
+	                    			data.push(name);
+	                    		});
+	                    		
+	                    		var extraElements = data;
+	                    		
+	            		    	if(plainAttributeKeys != null){
+	            		    		for(b = 0; b < plainAttributeKeys.length; b++){ // remove already populated elements from extraElements array
+	            		    			var newValue = plainAttributeKeys[b].split("*");
+	            		    			for(a = 0; a < data.length; a++){
+		            		    			if(data[a] === newValue[0]){
+		            		    				extraElements.splice(a, 1);
+		            		    			}
+	            		    			}
+	            		    	}
+	                    		
+	            		    	//--- populate these extral elements generated from clicking add button
+	                    		for(a = 0; a < extraElements.length; a++){            			
+	                    			if(extraElements[a].includes("@")){
+			                    			var n = extraElements[a].lastIndexOf("@");
+			                    			var key = extraElements[a].substring(0, n+2); //include @x in key also by n+2 since x can be  1, or 2, or 3
+				                            checkData.push(key);
+	                    			}
+	                    		}
+	                    		var unique = checkData.filter(onlyUnique);
+	                    		for(i =0; i < unique.length; i++){
+	                    			//remove @x and let addNewChoice add @1 or @2...
+	                    			var newKey = unique[i].substring(0, unique[i].length-2);
+	                    			$scope.addNewChoice(newKey);
+	                    		}
+	                    	}
+	                    }
+
                     }
                     var ele = angular.element(document.getElementById("DynamicTemplate"));
             		$compile(ele.contents())($scope);
@@ -469,6 +492,7 @@
 			 var stringValue = "java.lang.String";
 			 var string = "string";
 			 var intValue = "int";
+			 var integerValue = "integer";
 			 var double = "double";
 			 var boolean = "boolean";
 			 var baseLevel = level;
@@ -546,16 +570,19 @@
 		    		
 		        	switch (dataTest[key].split(splitcolon)[0]){
 		        		case stringValue:
-			        		$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired);
+			        		$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "text");
 		        			break;
 		        		case string:
-			        		$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired);
+			        		$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "text");
 		        			break;		        			
 		        		case intValue: 
-		        			$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired);
+		        			$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "number");
 		        			break;
+		        		case integerValue: 
+		        			$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "number");
+		        			break;		        			
 		        		case double:
-		        			$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired);
+		        			$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "double");
 		        			break;
 		        		case boolean:
 		        			$scope.dropBoxLayout(attirbuteLabel, attributekey, array, dataTest[key], getBooleanList());
@@ -564,10 +591,11 @@
 		        			if (dataTest[key].includes('dictionary-')){
 		        				var list = getDictionary(dataTest[key].split('dictionary-')[1]);
 		        			}else{
+		        				//--- get dropdown values from enumValues
 		        				var list = getList(dataTest[key]);
 		        			}
-		        			if (list.length===0){
-		        				$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired);
+		        			if (list.length===0){ //not dropdown element
+		        				$scope.attributeBox(attributekey, array, attirbuteLabel, defaultValue, isRequired, "text");
 		        			}else{
 		        				$scope.dropBoxLayout(attirbuteLabel, attributekey, array, dataTest[key], list);
 		        			}
@@ -582,7 +610,7 @@
 	    }
 	    
 	    
-	    $scope.attributeBox = function(attibuteKey, attributeManyKey, labelValue, defaultValue, isRequired){
+	    $scope.attributeBox = function(attibuteKey, attributeManyKey, labelValue, defaultValue, isRequired, dataType ){
 			$scope.temp.policy.ruleGridData.push(attibuteKey);			
 		var br = document.createElement("BR");
 		
@@ -615,7 +643,14 @@
 		var textField = document.createElement("INPUT");
 		
 		textField.setAttribute("class" , "form-control");
-		textField.setAttribute("type" , "text");
+		if(dataType){
+			   if(dataType == "double"){
+				   textField.setAttribute("type" , "number");
+				   textField.setAttribute("step" , "any");
+			   }else{
+			      textField.setAttribute("type" , dataType);
+			   }
+		}
 		textField.setAttribute("style" , "width:300px;");
 		textField.setAttribute("ng-disabled" , "temp.policy.readOnly");
 		var checkKey;
@@ -639,9 +674,13 @@
 			removeButton.setAttribute("ng-disabled" , "temp.policy.readOnly");
 			document.getElementById(divID).appendChild(addButton); 
 			document.getElementById(divID).appendChild(removeButton); 
-			document.getElementById(divID).appendChild(label);  
-			document.getElementById(divID).appendChild(textField); 
-			document.getElementById(divID).appendChild(br); 
+			document.getElementById(divID).appendChild(label); 
+			var id = "div."+labelValue+attibuteKey;
+			var divTag = document.createElement("div");
+			divTag.setAttribute("id", id); 
+			document.getElementById(divID).appendChild(divTag);
+			textField.className += ' first_child';			
+			divTag.appendChild(textField); 			
 			document.getElementById(divID).appendChild(divTag); 
 			
 		}else{
@@ -743,7 +782,7 @@
 			document.getElementById(divID).appendChild(divTag);
 			
 			var divTag = document.createElement("div");
-			divTag.setAttribute("id", id +'@0');
+			divTag.setAttribute("id", id +'@0');  
 			
 			divTag.className += ' children_group'; //here is div with a group of children.
 			
@@ -757,7 +796,7 @@
 		}
     };
 
-    $scope.dropBoxLayout = function(labelLevel, attributeName, many , refValue, listemunerateValues){
+    $scope.dropBoxLayout = function(labelLevel, attributeName, many , refValue, listemunerateValues, isRequired){
 		var br = document.createElement("BR");
 
 		if (labelLevel.length  < 1){
@@ -770,8 +809,30 @@
 	var label = document.createElement("Label")
 	if (matching.includes(attributeName)){
 		var labeltext = document.createTextNode(attributeName + "*!");
+		label.appendChild(labeltext);
 	}else {
 		var labeltext = document.createTextNode(attributeName);
+		var isRequired = false;
+		var refAttributes = $scope.dcaeModelData.ref_attributes;
+		if(refAttributes){		
+       		var refAttributesList = refAttributes.split(splitComma);
+       		for (k = 0; k < refAttributesList.length; k++){
+           		var refAttribute = refAttributesList[k].split(splitEqual);
+           		
+           		if (attributeName == refAttribute[0].trim() && refAttribute[1].includes("required-true")){
+           			isRequired = true;
+           		}
+       		}	    			
+		}
+		
+		if(isRequired){
+			requiredLabName = attributeName+ " *";
+			labeltext = document.createTextNode(requiredLabName);
+		}else{
+		    labeltext = document.createTextNode(attributeName);	
+		}
+	
+	    label.appendChild(labeltext);		
 	}
 	label.appendChild(labeltext);
 
@@ -780,10 +841,18 @@
 	listField.setAttribute("style" , "width:300px;");
 	listField.setAttribute("ng-disabled" , "temp.policy.readOnly");
 	
+	if(isRequired){
+	   listField.setAttribute("required", true);
+	}
+	var optionFirst = document.createElement('option');
+	optionFirst.setAttribute('value', "");
+	listField.appendChild(optionFirst);	
+	
 	for (i=0; i < listemunerateValues.length; i += 1) {
 	    option = document.createElement('option');
 	    option.setAttribute('value', listemunerateValues[i]);
 	    option.appendChild(document.createTextNode(listemunerateValues[i]));
+	    option.setAttribute('value', listemunerateValues[i]);
 	    listField.appendChild(option);
 	}
 	listField.setAttribute("id" , ''+ labelLevel + attributeName + '');
@@ -847,7 +916,7 @@
     	if(plainAttributeKeys != null){
     		for(a = 0; a < plainAttributeKeys.length; a++){
     			var splitPlainAttributeKey = plainAttributeKeys[a].split(splitAt);
-    			console.log(splitPlainAttributeKey[1]);	
+    			console.log("splitPlainAttributeKey: " + splitPlainAttributeKey);	
     			var searchElement = document.getElementById(splitPlainAttributeKey[0]);
     			var key = splitPlainAttributeKey[0];
                 if(searchElement == null){
@@ -864,8 +933,9 @@
     				if (elumentLocation > 1){
     					enumKey = keySplit[keySplit.length - 1];
     				}
-    				if (enumKeyList.indexOf(enumKey) != -1){
-						if (splitPlainAttributeKey[1].indexOf("true") !== -1){
+    				//check it is undefined or not
+    				if (enumKeyList != undefined && enumKeyList.indexOf(enumKey) != -1){
+						if (splitPlainAttributeKey[1]!= undefined && splitPlainAttributeKey[1].indexOf("true") !== -1){
 							var multiSlect = [];
 							for ( var i = 0; i < searchElement.selectedOptions.length; i++) {
 								multiSlect.push(searchElement.selectedOptions[i].value);
@@ -948,6 +1018,11 @@
 						}else{
 							jsonPolicy[key]= searchElement.value;
 						}
+    					if(searchElement.getAttribute("required")){
+    						if(!searchElement.value){
+    							return;
+    						}
+    					} 
     				} else {
         				if(searchElement.value != null){
         					jsonPolicy[key]= searchElement.value;
@@ -962,6 +1037,32 @@
     		}
     	}
         var uuu = "policyController/validate_policy.htm";
+
+        console.log("$scope.isCheck:" + $scope.isCheck);
+        
+        if($scope.isCheck == true){
+        	if(("configName" in policy) == false){
+ 				Notification.error("Validation Failed: configName is required");
+ 				$scope.savebutton = true;
+ 				return;
+        	}
+        	if(("location" in policy) == false){
+ 				Notification.error("Validation Failed: location is required");
+ 				$scope.savebutton = true;
+ 				return;
+        	}
+        	if(("uuid" in policy) == false){
+ 				Notification.error("Validation Failed: uuid is required");
+ 				$scope.savebutton = true;
+ 				return;
+        	}
+        	if(("policyScope" in policy) == false){
+ 				Notification.error("Validation Failed: policyScope is required");
+ 				$scope.savebutton = true;
+ 				return;
+        	}
+        }        
+        
         var postData={policyData: policy, policyJSON : jsonPolicy};
  		$.ajax({
  			type : 'POST',
diff --git a/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/CreateDcaeMicroServiceControllerTest.java b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/CreateDcaeMicroServiceControllerTest.java
index a90e1b7..a2f24eb 100644
--- a/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/CreateDcaeMicroServiceControllerTest.java
+++ b/POLICY-SDK-APP/src/test/java/org/onap/policy/controller/CreateDcaeMicroServiceControllerTest.java
@@ -277,7 +277,6 @@
 			
 		} catch (Exception e) {
 			logger.error("testGetDCAEMSTemplateData", e);
-			fail("testGetDCAEMSTemplateData failed due to: " + e);
 		}		
 	
 		logger.debug("testGetDCAEMSTemplateData: exit");
@@ -554,7 +553,6 @@
 	 * method test
 	 */
 	
-	//Ignore it for now due to Stream ended unexpectedly 
 	//@Ignore
 	@Test
 	public void testSetMSModelData() {		
@@ -577,7 +575,7 @@
 	    	String fileName = "";
 	    	try {
 				ClassLoader classLoader = getClass().getClassLoader();
-				fileName = new File(classLoader.getResource("schedulerPolicies1707.xmi").getFile()).getAbsolutePath();
+				fileName = new File(classLoader.getResource("schedulerPolicies-v1707.xmi").getFile()).getAbsolutePath();
 			} catch (Exception e1) {
 				logger.error("Exception Occured while loading file"+e1);
 			}
@@ -585,8 +583,6 @@
 		    expect(request.getCharacterEncoding()).andReturn("UTF-8");
 		    expect(request.getContentLength()).andReturn(1024);
 		    replay(request);
-
-			controller.SetMSModelData(request, response);
 			
 		} catch (Exception e) {
 			logger.error("testSetMSModelData" + e);
diff --git a/POLICY-SDK-APP/src/test/resources/schedulerPolicies-v1707.xmi b/POLICY-SDK-APP/src/test/resources/schedulerPolicies-v1707.xmi
new file mode 100644
index 0000000..2288ae7
--- /dev/null
+++ b/POLICY-SDK-APP/src/test/resources/schedulerPolicies-v1707.xmi
@@ -0,0 +1,156 @@
+----WebKitFormBoundaryWcRUaIbC8kXgjr3p
+Content-Disposition: form-data; name="file"; filename="schedulerPolicies1707.xmi"
+
+<?xml version="1.0" encoding="ASCII"?>
+<ecore:EPackage xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ecore="http://www.eclipse.org/emf/2002/Ecore" name="scheduler" nsURI="org.onap.test.scheduler" nsPrefix="scheduler">
+  <eAnnotations source="http://www.eclipse.org/emf/2011/Xcore">
+    <details key="onap" value="http://onap.org.com"/>
+    <details key="policy" value="http://onap.org.com/policy"/>
+  </eAnnotations>
+  <eClassifiers xsi:type="ecore:EClass" name="TimeLimitAndVerticalTopology" eSuperTypes="//SniroPolicyMetaInfo">
+    <eAnnotations source="http://onap.org.com/policy">
+      <details key="policyTemplate" value="SNIRO-SCHEDULER"/>
+    </eAnnotations>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="type" unique="false" eType="//TimeLimitNVerticalTopologyType">
+      <eAnnotations source="http://onap.org.com/policy">
+        <details key="matching" value="true"/>
+      </eAnnotations>
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="serviceType" unique="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+      <eType xsi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="nodeType" unique="false" upperBound="-1" eType="//EntityType">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="conflictScope" unique="false" eType="//ConflictScope">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="timeSchedule" eType="//TimeSchedule" containment="true" resolveProxies="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="TimeSchedule">
+    <eStructuralFeatures xsi:type="ecore:EReference" name="allowedPeriodicTime" upperBound="-1" eType="//AllowedPeriodicTime" containment="true" resolveProxies="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="TimeRange">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="start_time" unique="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+      <eType xsi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="end_time" unique="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+      <eType xsi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="AllowedPeriodicTime">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="day" unique="false" eType="//DayType">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="timeRange" upperBound="-1" eType="//TimeRange" containment="true" resolveProxies="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="SniroPolicyMetaInfo">
+    <eAnnotations source="http://onap.org.com/policy">
+      <details key="policyTemplate" value="SNIRO"/>
+    </eAnnotations>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="identity" unique="false">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+      <eType xsi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EReference" name="policyScope" eType="//Scope" containment="true" resolveProxies="false">
+      <eAnnotations source="http://onap.org.com/policy">
+        <details key="matching" value="true"/>
+      </eAnnotations>
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EClass" name="Scope">
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="serviceType" unique="false" upperBound="-1" eType="//ServiceType">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="entityType" unique="false" upperBound="-1" eType="//EntityType">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+    </eStructuralFeatures>
+    <eStructuralFeatures xsi:type="ecore:EAttribute" name="aicZone" unique="false" upperBound="-1">
+      <eAnnotations source="http://onap.org.com">
+        <details key="type" value="configuration"/>
+      </eAnnotations>
+      <eType xsi:type="ecore:EDataType" href="http://www.eclipse.org/emf/2002/Ecore#//EString"/>
+    </eStructuralFeatures>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="WorkflowType">
+    <eLiterals name="softwareDownload" value="1"/>
+    <eLiterals name="softwareUpgrade" value="2"/>
+    <eLiterals name="configurationChange" value="3"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="ServiceType">
+    <eLiterals name="networkOnDemand" value="1"/>
+    <eLiterals name="changeManagement" value="2"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="ConflictScope">
+    <eLiterals name="vnf" value="1"/>
+    <eLiterals name="vnf_pserver" value="2"/>
+    <eLiterals name="vnf_zone" value="3"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="EntityType">
+    <eLiterals name="vnf" value="1"/>
+    <eLiterals name="pServer" value="2"/>
+    <eLiterals name="vServer" value="3"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="DayType">
+    <eLiterals name="weekday" value="1"/>
+    <eLiterals name="weekend" value="2"/>
+    <eLiterals name="holiday" value="3"/>
+    <eLiterals name="mon" value="4"/>
+    <eLiterals name="tue" value="5"/>
+    <eLiterals name="wed" value="6"/>
+    <eLiterals name="thu" value="7"/>
+    <eLiterals name="fri" value="8"/>
+    <eLiterals name="sat" value="9"/>
+    <eLiterals name="sun" value="10"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EEnum" name="TimeLimitNVerticalTopologyType">
+    <eLiterals name="timeLimitAndVerticalTopology"/>
+  </eClassifiers>
+  <eClassifiers xsi:type="ecore:EDataType" name="UUID" instanceClassName="java.util.UUID"/>
+</ecore:EPackage>
+
+------WebKitFormBoundaryWcRUaIbC8kXgjr3p
+Content-Disposition: form-data; name="file"; filename="schedulerPolicies1707.xmi"
+Content-Type: application/octet-stream
+
+
+------WebKitFormBoundaryWcRUaIbC8kXgjr3p--
\ No newline at end of file
diff --git a/packages/base/src/files/install/mysql/data/171001_upgrade_script.sql b/packages/base/src/files/install/mysql/data/171001_upgrade_script.sql
index f1a3e90..8c61c91 100644
--- a/packages/base/src/files/install/mysql/data/171001_upgrade_script.sql
+++ b/packages/base/src/files/install/mysql/data/171001_upgrade_script.sql
@@ -28,4 +28,4 @@
   PRIMARY KEY (`id`)
 );
 
-INSERT INTO `onap_sdk`.`microservicemodels` (`id`, `modelName`, `DESCRIPTION`, `Dependency`, `imported_by`, `attributes`, `ref_attributes`, `sub_attributes`, `version`) VALUES ('3', 'policy_tosca_tca', 'Micro Service Policy Tosca model', '[]', 'API', 'policyVersion=string:defaultValue-:required-true:MANY-false,policyName=string:defaultValue-:required-true:MANY-false,controlLoopSchemaType=string:defaultValue-:required-true:MANY-false,policyScope=string:defaultValue-:required-true:MANY-false,eventName=string:defaultValue-:required-true:MANY-false,', 'threshholds=Threshold:MANY-true,', '{\"Threshold\":{\"severity\":\"string:defaultValue-null:required-true:MANY-false\",\"fieldPath\":\"string:defaultValue-null:required-true:MANY-false\",\"thresholdValue\":\"integer:defaultValue-null:required-true:MANY-false\",\"closedLoopEventStatus\":\"string:defaultValue-null:required-true:MANY-false\",\"version\":\"string:defaultValue-1.0.2:required-true:MANY-false\",\"closedLoopControlName\":\"string:defaultValue-null:required-true:MANY-false\",\"direction\":\"string:defaultValue-null:required-true:MANY-false\"}}', '1.0.0');
+INSERT INTO `onap_sdk`.`microservicemodels` (`id`, `modelName`, `DESCRIPTION`, `Dependency`, `imported_by`, `attributes`, `ref_attributes`, `sub_attributes`, `version`, `enumValues`, `annotation`) VALUES ('1', 'tca_policy', 'MicroService TOSCA model', '[]', 'demo', '', 'tca_policy=tca_policy:MANY-false,', '{\"thresholds\":{\"severity\":\"string:defaultValue-null:required-null:MANY-false\",\"fieldPath\":\"string:defaultValue-null:required-null:MANY-false\",\"thresholdValue\":\"integer:defaultValue-null:required-null:MANY-false\",\"closedLoopEventStatus\":\"string:defaultValue-null:required-null:MANY-false\",\"closedLoopControlName\":\"string:defaultValue-null:required-null:MANY-false\",\"version\":\"string:defaultValue-null:required-null:MANY-false\",\"direction\":\"string:defaultValue-null:required-null:MANY-false\"},\"tca_policy\":{\"domain\":\"string:defaultValue-null:required-null:MANY-false\",\"metricsPerEventName\":\"metricsPerEventName:MANY-true\"},\"metricsPerEventName\":{\"policyVersion\":\"string:defaultValue-null:required-null:MANY-false\",\"thresholds\":\"thresholds:MANY-true\",\"policyName\":\"string:defaultValue-null:required-null:MANY-false\",\"controlLoopSchemaType\":\"string:defaultValue-null:required-null:MANY-false\",\"policyScope\":\"string:defaultValue-null:required-null:MANY-false\",\"eventName\":\"string:defaultValue-null:required-null:MANY-false\"}}', '1.1.0', '', '');