[SDC-29] Amdocs OnBoard 1707 initial commit.

Change-Id: Ie4d12a3f574008b792899b368a0902a8b46b5370
Signed-off-by: AviZi <avi.ziv@amdocs.com>
diff --git a/openecomp-ui/src/nfvo-utils/DirectedGraph.js b/openecomp-ui/src/nfvo-utils/DirectedGraph.js
new file mode 100644
index 0000000..197625a
--- /dev/null
+++ b/openecomp-ui/src/nfvo-utils/DirectedGraph.js
@@ -0,0 +1,45 @@
+/*!
+ * 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.
+ */
+
+export default class Graph {
+	constructor() {
+		this.nodes = {};
+	}
+
+	addNode(node) {
+		this.nodes[node] = [];
+	}
+
+	hasNode(node) {
+		return this.nodes.hasOwnProperty(node);
+	}
+
+	addEdge(firstNode, secondNode, payload) {
+		if (!this.hasNode(firstNode)) {
+			this.addNode(firstNode);
+		}
+
+		if (!this.hasNode(secondNode)) {
+			this.addNode(secondNode);
+		}
+
+		this.nodes[firstNode].push({...payload, target: secondNode});
+	}
+
+	getEdges(node) {
+		return this.nodes[node];
+	}
+}
\ No newline at end of file
diff --git a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
index 0d27204..d58a245 100644
--- a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
+++ b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js
@@ -1,25 +1,23 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 import store from 'sdc-app/AppStore.js';
-import NotificationConstants from 'nfvo-components/notifications/NotificationConstants.js';
+import React from 'react';
+import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+import SubmitErrorResponse from 'nfvo-components/SubmitErrorResponse.jsx';
 
 function showVariablesInMessage(variables, msg) {
 	let regex;
@@ -45,6 +43,10 @@
 			msg = showVariablesInMessage(variables, msg);
 		}
 	}
+	else if (responseJSON.uploadDataErrors) {
+		title = i18n('Error: Upload Data Error');
+		msg = (<SubmitErrorResponse validationResponse={{uploadDataErrors: responseJSON.uploadDataErrors}} />);
+	}
 	else {
 		title = responseJSON.status;
 		msg = responseJSON.message;
@@ -60,12 +62,14 @@
 	else {
 		errorData = {
 			title: xhr.statusText,
-			msg: xhr.responseText
+			msg: xhr.responseText,			
 		};
 	}
 	store.dispatch({
-		type: NotificationConstants.NOTIFY_ERROR,
-		data: {...errorData}
+		type: modalActionTypes.GLOBAL_MODAL_ERROR,
+		data: {
+			...errorData			
+		}
 	});
 };
 
diff --git a/openecomp-ui/src/nfvo-utils/KeyMirror.js b/openecomp-ui/src/nfvo-utils/KeyMirror.js
index eb50d31..220fe07 100644
--- a/openecomp-ui/src/nfvo-utils/KeyMirror.js
+++ b/openecomp-ui/src/nfvo-utils/KeyMirror.js
@@ -1,23 +1,18 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 var keyMirror = function (obj) {
 	var ret = {};
 	var key;
@@ -41,4 +36,4 @@
 	return Object.freeze(ret);
 };
 
-export default keyMirror;
+export default keyMirror;
\ No newline at end of file
diff --git a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
index 2473473..c878c9e 100644
--- a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
+++ b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js
@@ -1,27 +1,19 @@
-/*-
- * ============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
+ * 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=========================================================
+ * 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.
  */
-
-import _extend from 'lodash/extend.js';
-import _clone from 'lodash/clone.js';
-import _defaults from 'lodash/defaults.js';
-import $ from 'jquery';
+import {RestfulAPI} from 'restful-js';
 import uuid from 'uuid-js';
 import md5 from 'md5';
 
@@ -30,30 +22,81 @@
 import Configuration from 'sdc-app/config/Configuration.js';
 import errorResponseHandler from './ErrorResponseHandler.js';
 
-const methodMap = {
-	'create': 'POST',
-	'update': 'PUT',
-	'delete': 'DELETE',
-	'read': 'GET'
-};
 const AUTHORIZATION_HEADER = 'X-AUTH-TOKEN';
 const STORAGE_AUTH_KEY = 'sdc-auth-token';
 const REQUEST_ID_HEADER = 'X-ECOMP-RequestID';
 const CONTENT_MD5_HEADER = 'Content-MD5';
-const namedParam = /{(\w+)}/g;
-const queryParamsNames = {
-	pageStart: 'pageStart',
-	pageSize: 'pageSize',
-	sortField: 'sortField',
-	sortDir: 'sortDir',
-	filtering: 'filter'
-};
 
 
+
+
+function applyMD5Header(options, data) {
+	if (options.md5) {
+		let headers = options.headers;
+		headers[CONTENT_MD5_HEADER] = window.btoa(md5(JSON.stringify(data)).toLowerCase());
+	}
+}
+
+function handleResponse(xhr) {
+	let authToken = xhr.getResponseHeader(AUTHORIZATION_HEADER);
+	let prevToken = this && this.headers && this.headers[AUTHORIZATION_HEADER];
+	if (authToken && authToken !== prevToken) {
+		if (authToken === 'null') {
+			localStorage.removeItem(STORAGE_AUTH_KEY);
+		} else {
+			localStorage.setItem(STORAGE_AUTH_KEY, authToken);
+		}
+	}
+}
+
+
+class RestAPIUtil extends RestfulAPI {
+
+	applySecurity(options, data) {
+		let headers = options.headers || (options.headers = {});
+
+		let authToken = localStorage.getItem(STORAGE_AUTH_KEY);
+		if (authToken) {
+			headers[AUTHORIZATION_HEADER] = authToken;
+		}
+
+		let attApiHeaders = Configuration.get('ATTApiHeaders'),
+			attUidHeader = attApiHeaders && attApiHeaders.userId;
+		if (attUidHeader) {
+			headers[attUidHeader.name] = attUidHeader.value;
+		}
+
+		headers[REQUEST_ID_HEADER] = uuid.create().toString();
+		applyMD5Header(options, data);
+	}
+
+	handleRequest(url, type, options = {}, data){
+		let success = options.success;
+		options.success = function (resp, textStatus, xhr) {
+			handleResponse.call(this, xhr);
+			if (success) {
+				success.call(options.context, {...resp}, textStatus, xhr);
+			}
+		};
+
+		if (DEBUG) {
+			console.log('--> Making REST call (' + type + '): ' + url);
+		}
+		return super.handleRequest(url, type, options, data);
+	}
+
+}
+
+const instance = new RestAPIUtil({
+	errorResponseHandler,
+	ajaxStartHandler: () => store.dispatch({type: LoaderConstants.SHOW}),
+	ajaxStopHandler: () => store.dispatch({type: LoaderConstants.HIDE})
+});
+
 // jQuery binary transport to download files through XHR
 // http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
 // https://github.com/henrya/js-jquery/tree/master/BinaryTransport
-$.ajaxTransport('+binary', function (options/*, originalOptions , jqXHR*/) {
+instance.$.ajaxTransport('+binary', function (options/*, originalOptions , jqXHR*/) {
 	// check for conditions and support for blob / arraybuffer response type
 	if (window.FormData && ((options.dataType && (options.dataType === 'binary')) ||
 		(options.data && ((window.ArrayBuffer && options.data instanceof ArrayBuffer) ||
@@ -62,19 +105,19 @@
 		return {
 			// create new XMLHttpRequest
 			send: function (headers, callback) {
-				// setup all variables
-				var xhr = new XMLHttpRequest(),
+				// setup all letiables
+				let xhr = new XMLHttpRequest(),
 					url = options.url,
 					type = options.type,
 					async = options.async || true,
-				// blob or arraybuffer. Default is blob
+					// blob or arraybuffer. Default is blob
 					dataType = options.responseType || 'blob',
 					data = options.data || null,
 					username = options.username || null,
 					password = options.password || null;
 
 				xhr.addEventListener('load', function () {
-					var data = {};
+					let data = {};
 					data[options.dataType] = xhr.response;
 					// make callback and send data
 					callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders());
@@ -83,7 +126,7 @@
 				xhr.open(type, url, async, username, password);
 
 				// setup custom headers
-				for (var i in headers) {
+				for (let i in headers) {
 					xhr.setRequestHeader(i, headers[i]);
 				}
 
@@ -96,193 +139,4 @@
 	}
 });
 
-$(document).ajaxStart(()=> store.dispatch({type: LoaderConstants.SHOW}));
-$(document).ajaxStop(()=> store.dispatch({type: LoaderConstants.HIDE}));
-
-function urlError() {
-	throw new Error('A "url" property or function must be specified');
-};
-
-export function makeQueryParams(options) {
-	var qParams = {};
-	if (options.pagination) {
-		qParams[queryParamsNames.pageStart] = options.pagination.pageStart;
-		qParams[queryParamsNames.pageSize] = options.pagination.pageSize;
-	}
-	if (options.sorting) {
-		qParams[queryParamsNames.sortField] = options.sorting.sortField;
-		qParams[queryParamsNames.sortDir] = options.sorting.sortDir;
-	}
-	if (options.filtering) {
-		qParams[queryParamsNames.filtering] = JSON.stringify(options.filtering);
-	}
-
-	return _defaults(qParams, options.qParams);
-}
-
-function appendQueryParam(p, value) {
-	var str = '';
-
-	if (value instanceof Array) {
-		if (value.length === 1) {
-			str = appendQueryParam(p, value[0]);
-		} else if (value.length > 1) {
-			str = appendQueryParam(p, value.shift()) + '&' + appendQueryParam(p, value);
-		}
-	} else {
-		str = p + '=' + encodeURIComponent(value);
-	}
-
-	return str;
-}
-
-function appendQueryString(url, qParams) {
-	var str = '';
-	for (var param in qParams) {
-		str += (str ? '&' : '') + appendQueryParam(param, qParams[param]);
-	}
-	return url + (str ? '?' : '') + str;
-}
-
-function composeURL(baseUrl, options) {
-	var url = baseUrl || urlError();
-	if (options.url) {
-		delete options.url;
-	}
-
-	var qParams = makeQueryParams(options);
-	url = appendQueryString(url, qParams);
-
-	var matches = url.match(namedParam);
-	if (matches) {
-		for (var i = 0; i < matches.length; i++) {
-			var param = matches[i].substring(1, matches[i].length - 1);
-			var value = (options.params && options.params[param]);
-
-			if (value === undefined) {
-				value = options[param];
-			}
-			url = url.replace(matches[i], encodeURIComponent(value));
-		}
-	}
-
-	return url;
-}
-
-function applyMD5Header(options, data) {
-	if (options.md5) {
-		let headers = options.headers;
-		headers[CONTENT_MD5_HEADER] = window.btoa(md5(JSON.stringify(data)).toLowerCase());
-	}
-}
-
-function applySecurity(options, data) {
-	var headers = options.headers || (options.headers = {});
-
-	var authToken = localStorage.getItem(STORAGE_AUTH_KEY);
-	if (authToken) {
-		headers[AUTHORIZATION_HEADER] = authToken;
-	}
-
-	var attApiHeaders = Configuration.get('ATTApiHeaders'),
-		attUidHeader = attApiHeaders && attApiHeaders.userId;
-	if (attUidHeader) {
-		headers[attUidHeader.name] = attUidHeader.value;
-	}
-
-	headers[REQUEST_ID_HEADER] = uuid.create().toString();
-
-	applyMD5Header(options, data);
-}
-
-function handleResponse(options) {
-	var authToken = options.xhr.getResponseHeader(AUTHORIZATION_HEADER);
-	var prevToken = options.headers && options.headers[AUTHORIZATION_HEADER];
-	if (authToken && authToken !== prevToken) {
-		if (authToken === 'null') {
-			localStorage.removeItem(STORAGE_AUTH_KEY);
-		} else {
-			localStorage.setItem(STORAGE_AUTH_KEY, authToken);
-		}
-	}
-}
-
-function sync(baseUrl, method, options, data) {
-
-	options = options ? _clone(options) : {};
-
-	var type = methodMap[method];
-	_defaults(options || (options = {}));
-	var params = {
-		type: type,
-		dataType: 'json'
-	};
-	params.url = composeURL(baseUrl, options);
-
-	if ((method === 'create' || method === 'update') && data instanceof FormData) {
-		params.contentType = 'multipart/form-data';
-		params.data = data;
-	}
-	else if (method === 'create' || method === 'update') {
-		params.contentType = 'application/json';
-		params.data = JSON.stringify(data);
-	}
-
-	if (params.type !== 'GET') {
-		params.processData = false;
-	}
-	var success = options.success;
-	options.success = function (resp) {
-		if (success) {
-			handleResponse(options);
-			success.call(options.context, _clone(resp), resp, options);
-		}
-	};
-
-	options.error = options.error || errorResponseHandler;
-
-	if (typeof options.progressCallback === 'function' && options.fileSize) {
-		const {fileSize} = options;
-		options.xhrFields = {
-			// add listener to XMLHTTPRequest object directly for progress (jquery doesn't have this yet)
-			onprogress: function (progress) {
-				// calculate upload progress
-				let percentage = Math.floor((progress.loaded / fileSize) * 100);
-				// log upload progress to console
-				//console.log('progress', percentage);
-				options.progressCallback(percentage);
-				if (percentage === 100) {
-					console.log('DONE!');
-				}
-			}
-		};
-	}
-
-	applySecurity(options, data);
-
-	if (DEBUG) {
-		console.log('--> Making REST call (' + type + '): ' + params.url);
-	}
-	var xhr = options.xhr = $.ajax(_extend(params, options));
-	return xhr;
-}
-
-export default {
-
-	fetch(baseUrl, options) {
-		return sync(baseUrl, 'read', options);
-	},
-
-	save(baseUrl, data, options) {
-		return sync(baseUrl, 'update', options, data);
-	},
-
-	create(baseUrl, data, options) {
-		return sync(baseUrl, 'create', options, data);
-	},
-
-	destroy(baseUrl, options) {
-		return sync(baseUrl, 'delete', options);
-	}
-
-};
+export default instance;
diff --git a/openecomp-ui/src/nfvo-utils/UUID.js b/openecomp-ui/src/nfvo-utils/UUID.js
index 314c98b..e1d4c54 100644
--- a/openecomp-ui/src/nfvo-utils/UUID.js
+++ b/openecomp-ui/src/nfvo-utils/UUID.js
@@ -1,23 +1,18 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 import UUID from 'uuid-js';
 
 let toCustomUUID = (uuid) => {
diff --git a/openecomp-ui/src/nfvo-utils/Validator.js b/openecomp-ui/src/nfvo-utils/Validator.js
new file mode 100644
index 0000000..708179e
--- /dev/null
+++ b/openecomp-ui/src/nfvo-utils/Validator.js
@@ -0,0 +1,110 @@
+/*!
+ * 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.
+ */
+
+import * as ValidatorJS from 'validator';
+import i18n from 'nfvo-utils/i18n/i18n.js';
+
+class Validator {
+	static get globalValidationFunctions() {
+		return {
+			required: value => value !== '',
+			maxLength: (value, length) => ValidatorJS.isLength(value, {max: length}),
+			minLength: (value, length) => ValidatorJS.isLength(value, {min: length}),
+			pattern: (value, pattern) => ValidatorJS.matches(value, pattern),
+			numeric: value => {
+				if (value === '') {
+					// to allow empty value which is not zero
+					return true;
+				}
+				return ValidatorJS.isNumeric(value);
+			},
+			maximum: (value, maxValue) => value <= maxValue,
+			minimum: (value, minValue) => value >= minValue,
+			maximumExclusive: (value, maxValue) => value < maxValue,
+			minimumExclusive: (value, minValue) => value > minValue,
+			alphanumeric: value => ValidatorJS.isAlphanumeric(value),
+			alphanumericWithSpaces: value => ValidatorJS.isAlphanumeric(value.replace(/ /g, '')),
+			validateName: value => ValidatorJS.isAlphanumeric(value.replace(/\s|\.|\_|\-/g, ''), 'en-US'),
+			validateVendorName: value => ValidatorJS.isAlphanumeric(value.replace(/[\x7F-\xFF]|\s/g, ''), 'en-US'),
+			freeEnglishText: value => ValidatorJS.isAlphanumeric(value.replace(/\s|\.|\_|\-|\,|\(|\)|\?/g, ''), 'en-US'),
+			email: value => ValidatorJS.isEmail(value),
+			ip: value => ValidatorJS.isIP(value),
+			url: value => ValidatorJS.isURL(value)
+		};
+	}
+
+	static get globalValidationMessagingFunctions() {
+		return {
+			required: () => i18n('Field is required'),
+			maxLength: (value, maxLength) => i18n('Field value has exceeded it\'s limit, {maxLength}. current length: {length}', {
+				length: value.length,
+				maxLength
+			}),
+			minLength: (value, minLength) => i18n('Field value should contain at least {minLength} characters.', {minLength}),
+			pattern: (value, pattern) => i18n('Field value should match the pattern: {pattern}.', {pattern}),
+			numeric: () => i18n('Field value should contain numbers only.'),
+			maximum: (value, maxValue) => i18n('Field value should be less or equal to: {maxValue}.', {maxValue}),
+			minimum: (value, minValue) => i18n('Field value should be at least: {minValue}.', {minValue: minValue.toString()}),
+			maximumExclusive: (value, maxValue) => i18n('Field value should be less than: {maxValue}.', {maxValue}),
+			minimumExclusive: (value, minValue) => i18n('Field value should be more than: {minValue}.', {minValue: minValue.toString()}),
+			alphanumeric: () => i18n('Field value should contain letters or digits only.'),
+			alphanumericWithSpaces: () => i18n('Field value should contain letters, digits or spaces only.'),
+			validateName: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'),
+			validateVendorName: ()=> i18n('Field value should contain English letters digits and spaces only.'),
+			freeEnglishText: ()=> i18n('Field value should contain  English letters, digits , spaces, underscores, dashes and dots only.'),
+			email: () => i18n('Field value should be a valid email address.'),
+			ip: () => i18n('Field value should be a valid ip address.'),
+			url: () => i18n('Field value should be a valid url address.'),
+			general: () => i18n('Field value is invalid.')
+		};
+	}
+
+	static validateItem(value, data, type) {
+		let validationFunc = this.globalValidationFunctions[type];
+		const isValid = validationFunc(value, data);
+		let errorText = '';
+		if (!isValid) {
+			errorText = this.globalValidationMessagingFunctions[type](value, data);
+		}
+		return {
+			isValid,
+			errorText
+		};
+	}
+
+	static validate(fieldName, value, validations, state, customValidations) {
+		let result = { isValid: true, errorText: '' };
+		for (let validation of validations) {
+			result = this.validateItem(value, validation.data, validation.type);
+			if (!result.isValid) {
+				return result;
+			}
+		}
+		if (customValidations) {
+			let validationFunc = customValidations[fieldName];
+			if (validationFunc) {
+				result = validationFunc(value, state);
+			}
+		}
+		return result;
+	}
+
+	static isItemNameAlreadyExistsInList({itemId, itemName, list}) {
+		return list[itemName] && list[itemName] !== itemId;
+	}
+}
+
+export default Validator;
diff --git a/openecomp-ui/src/nfvo-utils/i18n/i18n.js b/openecomp-ui/src/nfvo-utils/i18n/i18n.js
index 6458771..4d03ddb 100644
--- a/openecomp-ui/src/nfvo-utils/i18n/i18n.js
+++ b/openecomp-ui/src/nfvo-utils/i18n/i18n.js
@@ -1,23 +1,18 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 import IntlObj from 'intl';
 import IntlMessageFormatObj from 'intl-messageformat';
 import IntlRelativeFormatObj from 'intl-relativeformat';
diff --git a/openecomp-ui/src/nfvo-utils/json/JSONPointer.js b/openecomp-ui/src/nfvo-utils/json/JSONPointer.js
index a6e8198..f4c0d4e 100644
--- a/openecomp-ui/src/nfvo-utils/json/JSONPointer.js
+++ b/openecomp-ui/src/nfvo-utils/json/JSONPointer.js
@@ -1,23 +1,18 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 const JSONPointer = {
 
 	extractParentPointer(pointer) {
@@ -29,7 +24,7 @@
 		return lastPart;
 	},
 
-	extractParts(pointer) {
+	extractParts(pointer = '') {
 		return pointer.split('/').slice(1)
 			.map(part => part.replace(/~1/g, '/'))
 			.map(part => part.replace(/~0/g, '~'));
diff --git a/openecomp-ui/src/nfvo-utils/json/JSONSchema.js b/openecomp-ui/src/nfvo-utils/json/JSONSchema.js
index 8c7d8cf..3b3a9bf 100644
--- a/openecomp-ui/src/nfvo-utils/json/JSONSchema.js
+++ b/openecomp-ui/src/nfvo-utils/json/JSONSchema.js
@@ -1,23 +1,18 @@
-/*-
- * ============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
- * 
+ *
+ * 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=========================================================
+ * 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.
  */
-
 // import Ajv from 'ajv';
 import cloneDeep from 'lodash/cloneDeep.js';
 import JSONPointer from './JSONPointer.js';
@@ -40,6 +35,108 @@
 		return data;
 	}
 
+	// array of names of validation functions
+	setSupportedValidationFunctions(supportedValidationFunctions) {
+		this._supportedValidationFunctions = supportedValidationFunctions;
+	}
+
+	/* FYI - I was going to support "required" but then found out that server never sends it in its schema (it was a business decision. so leaving the code commented for now */
+	flattenSchema(supportedValidationFunctions) {
+		if (supportedValidationFunctions) { this.setSupportedValidationFunctions(supportedValidationFunctions); }
+		let genericFieldInfo = {};
+		if (this._schema && this._schema.properties) {
+			this.travelProperties(this._schema.properties, genericFieldInfo/*, this._schema.required*/);
+		}
+		return {genericFieldInfo};
+	}
+
+	extractGenericFieldInfo(item) {
+		let validationsArr = [];
+		let additionalInfo = { isValid: true, errorText: ''};
+		for (let value in item) {
+			if (this._supportedValidationFunctions.includes(value)) {
+				let validationItem = this.extractValidations(item, value);
+				validationsArr[validationsArr.length] = validationItem;
+			} else {
+				let enumResult = this.extractEnum(item, value);
+				if (enumResult !== null) {
+					additionalInfo.enum = enumResult;
+				}
+				else {
+					additionalInfo[value] = item[value];
+				}
+				/*if (required.includes (property)) {
+				 additionalInfo[value].isRequired = true ;
+				 }*/
+			}
+		}
+
+		additionalInfo.validations = validationsArr;
+		return additionalInfo;
+	}
+
+	extractValidations(item, value) {
+		let validationItem;
+		let data = item[value];
+		if (value === 'maximum') {
+			if (item.exclusiveMaximum) {
+				value = 'maximumExclusive';
+			}
+		}
+		if (value === 'minimum') {
+			if (item.exclusiveMinimum) {
+				value = 'minimumExclusive';
+			}
+		}
+		validationItem = {type: value, data: data};
+		return validationItem;
+	}
+
+	extractEnum(item, value) {
+		let enumResult = null;
+		if (value === 'type' && item[value] === 'array') {
+			let items = item.items;
+			if (items && items.enum && items.enum.length > 0) {
+				let values = items.enum
+					.filter(value => value)
+					.map(value => ({enum: value, title: value}));
+				enumResult = values;
+			}
+		}
+		else if (value === 'enum') {
+			let items = item[value];
+			if (items && items.length > 0) {
+				let values = items
+					.filter(value => value)
+					.map(value => ({enum: value, title: value}));
+				enumResult = values;
+			}
+		}
+		return enumResult;
+	}
+
+	travelProperties(properties, genericFieldDefs, /*required = [],*/ pointer = ''){
+		let newPointer = pointer;
+		for (let property in properties) {
+			newPointer = newPointer ? newPointer + '/' + property : property;
+			if (properties[property].properties) {
+				this.travelProperties(properties[property].properties, genericFieldDefs /*, properties[property].required*/, newPointer);
+			}
+			else if (properties[property].$ref){
+				let fragment = this._getSchemaFragmentByRef(properties[property].$ref);
+				if (fragment.properties) {
+					this.travelProperties(fragment.properties, genericFieldDefs /*, properties[property].required*/, newPointer);
+				} else {
+					genericFieldDefs[newPointer] = this.extractGenericFieldInfo(fragment.properties);
+				}
+			}
+			else {
+				genericFieldDefs[newPointer] = this.extractGenericFieldInfo(properties[property]);
+			}
+			newPointer = pointer;
+		}
+	}
+
 	getTitle(pointer) {
 		return this._getSchemaFragment(pointer).title;
 	}
@@ -73,12 +170,12 @@
 
 	getMaxValue(pointer) {
 		const fragment = this._getSchemaFragment(pointer);
-		return fragment && fragment.maximum;
+		return fragment && fragment.exclusiveMaximum ? fragment.maximum - 1 : fragment.maximum;
 	}
 
 	getMinValue(pointer) {
 		const fragment = this._getSchemaFragment(pointer);
-		return fragment && fragment.minimum;
+		return fragment && fragment.exclusiveMinimum ? fragment.minimum : fragment.minimum;
 	}
 
 	isString(pointer) {
diff --git a/openecomp-ui/src/nfvo-utils/sortByStringProperty.js b/openecomp-ui/src/nfvo-utils/sortByStringProperty.js
new file mode 100644
index 0000000..b415dd7
--- /dev/null
+++ b/openecomp-ui/src/nfvo-utils/sortByStringProperty.js
@@ -0,0 +1,18 @@
+/*!
+ * 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.
+ */
+export default function sortByStringProperty(array, property) {
+	return [...array].sort((a, b) => a[property].toLowerCase().localeCompare(b[property].toLowerCase()));
+}