Initial OpenECOMP MSO commit

Change-Id: Ia6a7574859480717402cc2f22534d9973a78fa6d
Signed-off-by: ChrisC <cc697w@intl.att.com>
diff --git a/adapters/mso-network-adapter/README b/adapters/mso-network-adapter/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/adapters/mso-network-adapter/README
diff --git a/adapters/mso-network-adapter/WebContent/META-INF/MANIFEST.MF b/adapters/mso-network-adapter/WebContent/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..5e94951
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/META-INF/MANIFEST.MF
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0

+Class-Path: 

+

diff --git a/adapters/mso-network-adapter/WebContent/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector b/adapters/mso-network-adapter/WebContent/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector
new file mode 100644
index 0000000..1281d32
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/META-INF/services/com.woorea.openstack.base.client.OpenStackClientConnector
@@ -0,0 +1 @@
+com.woorea.openstack.connector.HttpClientConnector
\ No newline at end of file
diff --git a/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-deployment-structure.xml b/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-deployment-structure.xml
new file mode 100644
index 0000000..58ddb4a
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-deployment-structure.xml
@@ -0,0 +1,16 @@
+<jboss-deployment-structure>

+	<deployment>

+		<!-- Exclusions allow you to prevent the server from automatically adding some dependencies -->

+		<exclusions>

+			<module name="org.apache.log4j" />

+			<module name="org.slf4j" />

+			<module name="org.slf4j.impl" />

+		</exclusions>

+		<dependencies>

+			    <module name="org.jboss.jandex" slot="main" />

+                <module name="org.javassist" slot="main" />

+                <module name="org.antlr" slot="main" />

+                <module name="org.dom4j" slot="main" />

+		</dependencies>

+	</deployment>

+</jboss-deployment-structure>
\ No newline at end of file
diff --git a/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-web.xml b/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-web.xml
new file mode 100644
index 0000000..251a78b
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/WEB-INF/jboss-web.xml
@@ -0,0 +1,3 @@
+<jboss-web>

+	<context-root>networks</context-root>

+</jboss-web>
\ No newline at end of file
diff --git a/adapters/mso-network-adapter/WebContent/WEB-INF/web.xml b/adapters/mso-network-adapter/WebContent/WEB-INF/web.xml
new file mode 100644
index 0000000..a0c726a
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/WEB-INF/web.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
+  <display-name>mso-network-adapter</display-name>
+
+   <context-param>
+	<param-name>resteasy.jndi.resources</param-name>
+	<param-value>java:module/MsoPropertiesFactory,java:module/CloudConfigFactory</param-value>
+   </context-param>
+
+   <context-param>
+  	<param-name>log.configuration</param-name>
+  	<param-value>logback.network.xml</param-value>
+  </context-param>
+  <context-param>
+  	<param-name>mso.configuration</param-name>
+  	<param-value>MSO_PROP_NETWORK_ADAPTER=mso.network.properties,MSO_PROP_TOPOLOGY=topology.properties</param-value>
+  </context-param>
+  <context-param>
+  	<param-name>mso.cloud_config.configuration</param-name>
+  	<param-value>cloud_config.json=2</param-value>
+  </context-param>
+  <context-param>
+    <param-name>resteasy.resources</param-name>
+    <param-value>
+		org.openecomp.mso.MsoStatusHandler,
+		org.openecomp.mso.logger.MsoLoggingServlet,
+		org.openecomp.mso.adapters.network.HealthCheckHandler,
+		org.openecomp.mso.adapters.network.NetworkAdapterRest
+    </param-value>
+  </context-param>
+  <context-param>
+    <param-name>resteasy.servlet.mapping.prefix</param-name>
+    <param-value>/rest</param-value>
+  </context-param>
+  <servlet>
+    <servlet-name>Resteasy</servlet-name>
+    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
+  </servlet>
+  <servlet-mapping>
+    <servlet-name>Resteasy</servlet-name>
+    <url-pattern>/rest/*</url-pattern>
+  </servlet-mapping>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>SoapRequests</web-resource-name>
+            <description>Soap Ingress Requests</description>
+            <url-pattern>/NetworkAdapter</url-pattern>
+            <url-pattern>/NetworkAdapterAsync</url-pattern>
+            <http-method>POST</http-method>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>BPEL-Client</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>SiteStatus</web-resource-name>
+            <description>SiteStatus APIs</description>
+            <url-pattern>/rest/setStatus/*</url-pattern>
+            <http-method>POST</http-method>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>SiteControl-Client</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>RestRequests</web-resource-name>
+            <description>Rest Ingress Requests</description>
+            <url-pattern>/rest/v1/networks/*</url-pattern>
+            <http-method>DELETE</http-method>
+            <http-method>GET</http-method>
+            <http-method>POST</http-method>
+            <http-method>PUT</http-method>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>BPEL-Client</role-name>
+        </auth-constraint>
+    </security-constraint>
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>ApplicationRealm</realm-name>
+    </login-config>
+    <security-role>
+        <role-name>BPEL-Client</role-name>
+    </security-role>
+    <security-role>
+        <role-name>SiteControl-Client</role-name>
+    </security-role>
+  <filter>
+		<filter-name>LogFilter</filter-name>
+		<filter-class>org.openecomp.mso.logger.LogFilter</filter-class>	
+  </filter>
+    <filter-mapping>
+		<filter-name>LogFilter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+  <welcome-file-list>
+    <welcome-file>check.html</welcome-file>
+  </welcome-file-list>
+</web-app>
+
diff --git a/adapters/mso-network-adapter/WebContent/check.html b/adapters/mso-network-adapter/WebContent/check.html
new file mode 100644
index 0000000..00f37d6
--- /dev/null
+++ b/adapters/mso-network-adapter/WebContent/check.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>

+<html>

+<head>

+<meta charset="ISO-8859-1">

+<title>Health Check</title>

+</head>

+<body>

+Application ready

+</body>

+</html>
\ No newline at end of file
diff --git a/adapters/mso-network-adapter/pom.xml b/adapters/mso-network-adapter/pom.xml
new file mode 100644
index 0000000..3991bf3
--- /dev/null
+++ b/adapters/mso-network-adapter/pom.xml
@@ -0,0 +1,154 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+	<parent>
+		<groupId>org.openecomp.mso</groupId>
+		<artifactId>adapters</artifactId>
+		<version>0.0.4-SNAPSHOT</version>
+	</parent>
+	<groupId>org.openecomp.mso.adapters</groupId>
+	<artifactId>mso-network-adapter</artifactId>
+	<packaging>war</packaging>
+	<name>mso-network-adapter</name>
+	<description>Web service endpoint for Network operations</description>
+
+	<!-- <properties> -->
+	<!-- <project.build.sourceEncoding/> -->
+	<!-- <project.reporting.outputEncoding/> -->
+	<!-- </properties> -->
+
+	<build>
+		<finalName>${project.artifactId}-${project.version}</finalName>
+		<plugins>
+			<plugin>
+				<artifactId>maven-war-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<warSourceDirectory>WebContent</warSourceDirectory>
+					<failOnMissingWebXml>false</failOnMissingWebXml>
+					<attachClasses>true</attachClasses>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.jvnet.jax-ws-commons</groupId>
+				<artifactId>jaxws-maven-plugin</artifactId>
+				<version>2.3</version>
+				<executions>
+					<execution>
+						<goals>
+							<goal>wsgen</goal>
+						</goals>
+					</execution>
+				</executions>
+				<configuration>
+					<verbose>true</verbose>
+					<sei>org.openecomp.mso.adapters.network.MsoNetworkAdapterImpl</sei>
+					<genWsdl>true</genWsdl>
+					<inlineSchemas>true</inlineSchemas>
+				</configuration>
+				<dependencies>
+					<dependency>
+						<groupId>com.sun.xml.ws</groupId>
+						<artifactId>jaxws-tools</artifactId>
+						<version>2.2.7</version>
+					</dependency>
+					<dependency>
+						<groupId>org.openecomp.mso.adapters</groupId>
+						<artifactId>mso-adapter-utils</artifactId>
+						<version>${project.version}</version>
+					</dependency>
+				</dependencies>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<!--This plugin's configuration is used to store Eclipse m2e settings 
+					only. It has no influence on the Maven build itself. -->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>
+											org.jvnet.jax-ws-commons
+										</groupId>
+										<artifactId>
+											jaxws-maven-plugin
+										</artifactId>
+										<versionRange>
+											[2.3,)
+										</versionRange>
+										<goals>
+											<goal>wsgen</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<ignore></ignore>
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+
+	<dependencies>
+		<dependency>
+			<groupId>javax</groupId>
+			<artifactId>javaee-web-api</artifactId>
+			<version>6.0</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.mso.adapters</groupId>
+			<artifactId>mso-adapter-utils</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.mso.adapters</groupId>
+			<artifactId>mso-network-adapter-async-client</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.mso.adapters</groupId>
+			<artifactId>mso-adapters-rest-interface</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.mockito</groupId>
+			<artifactId>mockito-all</artifactId>
+			<version>1.10.19</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>javax.servlet</groupId>
+			<artifactId>javax.servlet-api</artifactId>
+			<version>3.1.0</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.jboss.spec.javax.ejb</groupId>
+			<artifactId>jboss-ejb-api_3.2_spec</artifactId>
+			<version>1.0.0.Final</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.jboss.ejb3</groupId>
+			<artifactId>jboss-ejb3-ext-api</artifactId>
+			<version>2.2.0.Final</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.openecomp.mso</groupId>
+			<artifactId>status-control</artifactId>
+			<version>${project.version}</version>
+		</dependency>
+
+	</dependencies>
+</project>
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java
new file mode 100644
index 0000000..dcd12d2
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/BpelRestClient.java
@@ -0,0 +1,304 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import java.io.IOException;
+import java.util.Set;
+import java.util.TreeSet;
+
+import javax.xml.bind.DatatypeConverter;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.properties.MsoJavaProperties;
+import org.openecomp.mso.properties.MsoPropertiesException;
+import org.openecomp.mso.properties.MsoPropertiesFactory;
+
+/**
+ * This is the class that is used to POST replies from the MSO adapters to the BPEL engine.
+ * It can be configured via property file, or modified using the member methods.
+ * The properties to use are:
+ * org.openecomp.mso.adapters.vnf.bpelauth  encrypted authorization string to send to BEPL engine
+ * org.openecomp.mso.adapters.vnf.sockettimeout socket timeout value
+ * org.openecomp.mso.adapters.vnf.connecttimeout connect timeout value
+ * org.openecomp.mso.adapters.vnf.retrycount number of times to retry failed connections
+ * org.openecomp.mso.adapters.vnf.retryinterval interval (in seconds) between retries
+ * org.openecomp.mso.adapters.vnf.retrylist list of response codes that will trigger a retry (the special code
+ * 			900 means "connection was not established")
+ */
+public class BpelRestClient {
+	public  static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER";
+	private static final String PROPERTY_DOMAIN          = "org.openecomp.mso.adapters.network";
+	private static final String BPEL_AUTH_PROPERTY       = PROPERTY_DOMAIN+".bpelauth";
+	private static final String SOCKET_TIMEOUT_PROPERTY  = PROPERTY_DOMAIN+".sockettimeout";
+	private static final String CONN_TIMEOUT_PROPERTY    = PROPERTY_DOMAIN+".connecttimeout";
+	private static final String RETRY_COUNT_PROPERTY     = PROPERTY_DOMAIN+".retrycount";
+	private static final String RETRY_INTERVAL_PROPERTY  = PROPERTY_DOMAIN+".retryinterval";
+	private static final String RETRY_LIST_PROPERTY      = PROPERTY_DOMAIN+".retrylist";
+	private static final String ENCRYPTION_KEY           = "aa3871669d893c7fb8abbcda31b88b4f";
+	private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+
+	/** Default socket timeout (in seconds) */
+	public static final int DEFAULT_SOCKET_TIMEOUT = 5;
+	/** Default connect timeout (in seconds) */
+	public static final int DEFAULT_CONNECT_TIMEOUT = 5;
+	/** By default, retry up to five times */
+	public static final int DEFAULT_RETRY_COUNT = 5;
+	/** Default interval to wait between retries (in seconds), negative means use backoff algorithm */
+	public static final int DEFAULT_RETRY_INTERVAL = -15;
+	/** Default list of response codes to trigger a retry */
+	public static final String DEFAULT_RETRY_LIST = "408,429,500,502,503,504,900";	// 900 is "connection failed"
+	/** Default credentials */
+	public static final String DEFAULT_CREDENTIALS = "";
+
+	// Properties of the BPEL client -- all are configurable
+	private int socketTimeout;
+	private int connectTimeout;
+	private int retryCount;
+	private int retryInterval;
+	private Set<Integer> retryList;
+	private String credentials;
+
+	// last response from BPEL engine
+	private int lastResponseCode;
+	private String lastResponse;
+
+	/**
+	 * Create a client to send results to the BPEL engine, using configuration from the
+	 * MSO_PROP_NETWORK_ADAPTER properties.
+	 */
+	public BpelRestClient() {
+		socketTimeout  = DEFAULT_SOCKET_TIMEOUT;
+		connectTimeout = DEFAULT_CONNECT_TIMEOUT;
+		retryCount     = DEFAULT_RETRY_COUNT;
+		retryInterval  = DEFAULT_RETRY_INTERVAL;
+		setRetryList(DEFAULT_RETRY_LIST);
+		credentials    = DEFAULT_CREDENTIALS;
+		lastResponseCode = 0;
+		lastResponse = "";
+
+		try {
+			MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
+			MsoJavaProperties jp = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_NETWORK_ADAPTER);
+			socketTimeout  = jp.getIntProperty(SOCKET_TIMEOUT_PROPERTY, DEFAULT_SOCKET_TIMEOUT);
+			connectTimeout = jp.getIntProperty(CONN_TIMEOUT_PROPERTY,   DEFAULT_CONNECT_TIMEOUT);
+			retryCount     = jp.getIntProperty(RETRY_COUNT_PROPERTY,    DEFAULT_RETRY_COUNT);
+			retryInterval  = jp.getIntProperty(RETRY_INTERVAL_PROPERTY, DEFAULT_RETRY_INTERVAL);
+			setRetryList(jp.getProperty(RETRY_LIST_PROPERTY, DEFAULT_RETRY_LIST));
+			credentials    = jp.getEncryptedProperty(BPEL_AUTH_PROPERTY, DEFAULT_CREDENTIALS, ENCRYPTION_KEY);
+		} catch (MsoPropertiesException e) {
+			String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
+			LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Unable to get properties", e);
+		}
+	}
+
+	public int getSocketTimeout() {
+		return socketTimeout;
+	}
+
+	public void setSocketTimeout(int socketTimeout) {
+		this.socketTimeout = socketTimeout;
+	}
+
+	public int getConnectTimeout() {
+		return connectTimeout;
+	}
+
+	public void setConnectTimeout(int connectTimeout) {
+		this.connectTimeout = connectTimeout;
+	}
+
+	public int getRetryCount() {
+		return retryCount;
+	}
+
+	public void setRetryCount(int retryCount) {
+		if (retryCount < 0)
+			retryCount = DEFAULT_RETRY_COUNT;
+		this.retryCount = retryCount;
+	}
+
+	public int getRetryInterval() {
+		return retryInterval;
+	}
+
+	public void setRetryInterval(int retryInterval) {
+		this.retryInterval = retryInterval;
+	}
+
+	public String getCredentials() {
+		return credentials;
+	}
+
+	public void setCredentials(String credentials) {
+		this.credentials = credentials;
+	}
+
+	public String getRetryList() {
+		if (retryList.size() == 0)
+			return "";
+		String t = retryList.toString();
+		return t.substring(1, t.length()-1);
+	}
+
+	public void setRetryList(String retryList) {
+		Set<Integer> s = new TreeSet<Integer>();
+		for (String t : retryList.split("[, ]")) {
+			try {
+				s.add(Integer.parseInt(t));
+			} catch (NumberFormatException x) {
+				// ignore
+			}
+		}
+		this.retryList = s;
+	}
+
+	public int getLastResponseCode() {
+		return lastResponseCode;
+	}
+
+	public String getLastResponse() {
+		return lastResponse;
+	}
+
+	/**
+	 * Post a response to the URL of the BPEL engine.  As long as the response code is one of those in
+	 * the retryList, the post will be retried up to "retrycount" times with an interval (in seconds)
+	 * of "retryInterval".  If retryInterval is negative, then each successive retry interval will be
+	 * double the previous one.
+	 * @param toBpelStr the content (XML or JSON) to post
+	 * @param bpelUrl the URL to post to
+	 * @param isxml true if the content is XML, otherwise assumed to be JSON
+	 * @return true if the post succeeded, false if all retries failed
+	 */
+	public boolean bpelPost(final String toBpelStr, final String bpelUrl, final boolean isxml)  {
+		debug("Sending response to BPEL: " + toBpelStr);
+		int totalretries = 0;
+		int retryint = retryInterval;
+		while (true) {
+			sendOne(toBpelStr, bpelUrl, isxml);
+			// Note: really should handle response code 415 by switching between content types if needed
+			if (!retryList.contains(lastResponseCode)) {
+				debug("Got response code: " + lastResponseCode + ": returning.");
+				return true;
+			}
+			if (totalretries >= retryCount) {
+				debug("Retried " + totalretries + " times, giving up.");
+				LOGGER.error(MessageEnum.RA_SEND_VNF_NOTIF_ERR, "Could not deliver response to BPEL after "+totalretries+" tries: "+toBpelStr, "Camunda", "", MsoLogger.ErrorCode.DataError, "Could not deliver response to BPEL");
+				return false;
+			}
+			totalretries++;
+			int sleepinterval = retryint;
+			if (retryint < 0) {
+				// if retry interval is negative double the retry on each pass
+				sleepinterval = -retryint;
+				retryint *= 2;
+			}
+			debug("Sleeping for " + sleepinterval + " seconds.");
+			try {
+				Thread.sleep(sleepinterval * 1000L);
+			} catch (InterruptedException e) {
+				// ignore
+			}
+		}
+	}
+	private void debug(String m) {
+		LOGGER.debug(m);
+//		System.err.println(m);
+	}
+	private void sendOne(final String toBpelStr, final String bpelUrl, final boolean isxml) {
+		LOGGER.debug("Sending to BPEL server: "+bpelUrl);
+		LOGGER.debug("Content is: "+toBpelStr);
+
+        //POST
+		HttpPost post = new HttpPost(bpelUrl);
+		if (credentials != null && !credentials.isEmpty())
+			post.addHeader("Authorization", "Basic " + DatatypeConverter.printBase64Binary(credentials.getBytes()));
+
+        //ContentType
+        ContentType ctype = isxml ? ContentType.APPLICATION_XML : ContentType.APPLICATION_JSON;
+        post.setEntity(new StringEntity(toBpelStr, ctype));
+
+        //Timeouts
+		RequestConfig requestConfig = RequestConfig
+			.custom()
+			.setSocketTimeout(socketTimeout * 1000)
+			.setConnectTimeout(connectTimeout * 1000)
+			.build();
+		post.setConfig(requestConfig);
+
+        //Client 4.3+
+		//Execute & GetResponse
+		try (CloseableHttpClient client = HttpClients.createDefault();
+             CloseableHttpResponse response = client.execute(post)) {
+			if (response != null) {
+				lastResponseCode = response.getStatusLine().getStatusCode();
+				HttpEntity entity = response.getEntity();
+				lastResponse = (entity != null) ? EntityUtils.toString(entity) : "";
+			} else {
+				lastResponseCode = 900;
+				lastResponse = "";
+			}
+		} catch (Exception e) {
+			String error = "Error sending Bpel notification:" + toBpelStr;
+			LOGGER.error (MessageEnum.RA_SEND_VNF_NOTIF_ERR, error, "Camunda", "", MsoLogger.ErrorCode.AvailabilityError, "Exception sending Bpel notification", e);
+			lastResponseCode = 900;
+			lastResponse = "";
+		}
+		LOGGER.debug("Response code from BPEL server: "+lastResponseCode);
+		LOGGER.debug("Response body is: "+lastResponse);
+	}
+
+	public static void main(String[] a) throws MsoPropertiesException {
+		final String bpelengine = "http://mtmac1.research.att.com:8080/catch.jsp";
+		final String propfile = "/tmp/mso.vnf.properties";
+		// "/Users/eby/src/mso.rest/mso/packages/mso-config-centralized/mso-po-adapter-config/mso.vnf.properties"
+		final String xml =
+			"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+			"<updateVolumeGroupResponse><volumeGroupId>1464013300723</volumeGroupId><volumeGroupOutputs>" +
+	        "<entry><key>clyde</key><value>10</value></entry>" +
+	        "<entry><key>wayne</key><value>99</value></entry>" +
+	        "<entry><key>mickey</key><value>7</value></entry>" +
+	        "</volumeGroupOutputs></updateVolumeGroupResponse>";
+
+		MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
+		msoPropertiesFactory.initializeMsoProperties (MSO_PROP_NETWORK_ADAPTER, propfile);
+
+		BpelRestClient bc = new BpelRestClient();
+		System.out.println(bc.getRetryList());
+		System.out.println(bc.getCredentials()); // poAvos:Domain2.0!
+
+		bc.bpelPost(xml, bpelengine, true);
+		System.out.println("respcode = "+bc.getLastResponseCode());
+		System.out.println("resp = "+bc.getLastResponse());
+	}
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java
new file mode 100644
index 0000000..6e2644d
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRef.java
@@ -0,0 +1,78 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
+
+public class ContrailPolicyRef {
+	private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+	 
+	@JsonProperty("network_policy_refs_data_sequence")
+	private ContrailPolicyRefSeq seq;
+	
+	public JsonNode toJsonNode()
+	{
+		JsonNode node = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper(); 
+			node = mapper.convertValue(this, JsonNode.class);
+		}
+		catch (Exception e)
+		{
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e);
+		}
+		
+		return node;
+	}
+	
+	public String toJsonString()
+	{
+		String jsonString = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper(); 
+			jsonString = mapper.writeValueAsString(this);
+		}
+		catch (Exception e)
+		{
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "Error creating JsonString for Contrail Policy Ref", "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Policy Ref", e);
+		}
+		
+		return jsonString;
+	}
+	
+	public void populate(String major, String minor)
+	{
+		seq = new ContrailPolicyRefSeq(major, minor);
+		return;
+	}
+	
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java
new file mode 100644
index 0000000..b5d7502
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailPolicyRefSeq.java
@@ -0,0 +1,65 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class ContrailPolicyRefSeq {
+	
+	@JsonProperty("network_policy_refs_data_sequence_major")
+	private String major;
+	
+	@JsonProperty("network_policy_refs_data_sequence_minor")
+	private String minor;
+
+	public ContrailPolicyRefSeq() {
+	}
+	
+	public ContrailPolicyRefSeq(String major, String minor) {
+		super();
+		this.major = major;
+		this.minor = minor;
+	}
+
+	public String getMajor() {
+		return major;
+	}
+
+	public void setMajor(String major) {
+		this.major = major;
+	}
+
+	public String getMinor() {
+		return minor;
+	}
+
+	public void setMinor(String minor) {
+		this.minor = minor;
+	}
+
+	@Override
+	public String toString() {
+		return "ContrailPolicyRefSeq [major=" + major + ", minor=" + minor
+				+ "]";
+	} 
+
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java
new file mode 100644
index 0000000..3df1014
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnet.java
@@ -0,0 +1,196 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.beans.Pool;
+import org.openecomp.mso.openstack.beans.Subnet;
+import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty;
+
+public class ContrailSubnet {
+	private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_subnet")
+	private ContrailSubnetIp subnet = new ContrailSubnetIp();
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_default_gateway")
+	private String default_gateway;
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_name")
+	private String subnet_name;
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_enable_dhcp")
+	private Boolean enable_dhcp;
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_addr_from_start")
+	private Boolean addr_from_start = true;
+	
+	/** future - leave this commented
+	private String subnet_uuid;
+	private String dns_server_address;
+	private List<String> dns_nameservers;
+	private String dhcp_option_list;
+	private String host_routes;
+	**/
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools")
+	private List<ContrailSubnetPool> allocation_pools =  new ArrayList <ContrailSubnetPool> ();
+
+	public ContrailSubnet() {
+		super();
+	}
+
+	public String getDefault_gateway() {
+		return default_gateway;
+	}
+
+	public void setDefault_gateway(String default_gateway) {
+		this.default_gateway = default_gateway;
+	}
+
+	public ContrailSubnetIp getSubnet() {
+		return subnet;
+	}
+
+	public void setSubnet(ContrailSubnetIp subnet) {
+		this.subnet = subnet;
+	}
+
+	public Boolean isEnable_dhcp() {
+		return enable_dhcp;
+	}
+
+	public void setEnable_dhcp(Boolean enable_dhcp) {
+		this.enable_dhcp = enable_dhcp;
+	}
+
+	public String getSubnet_name() {
+		return subnet_name;
+	}
+
+	public void setSubnet_name(String subnet_name) {
+		this.subnet_name = subnet_name;
+	}
+
+	public List<ContrailSubnetPool> getAllocation_pools() {
+		return allocation_pools;
+	}
+
+	public void setPools(List<ContrailSubnetPool> allocation_pools) {
+		this.allocation_pools = allocation_pools;
+	}
+
+	public Boolean isAddr_from_start() {
+		return addr_from_start;
+	}
+
+	public void setAddr_from_start(Boolean addr_from_start) {
+		this.addr_from_start = addr_from_start;
+	}
+
+	public JsonNode toJsonNode()
+	{
+		JsonNode node = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper();
+			node = mapper.convertValue(this, JsonNode.class);
+		}
+		catch (Exception e)
+		{
+			String error = "Error creating JsonNode for Contrail Subnet:" + subnet_name;
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonNode for Contrail Subnet", e);
+		}
+		
+		return node;
+	}
+	
+	public String toJsonString()
+	{
+		String jsonString = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper();
+			jsonString = mapper.writeValueAsString(this);
+		}
+		catch (Exception e)
+		{
+			String error = "Error creating JsonString for Contrail Subnet:" + subnet_name;
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.SchemaError, "Exception creating JsonString for Contrail Subnet", e);
+		}
+		
+		return jsonString;
+	}
+	//poulate contrail subnet with input(from bopel) subnet
+	public void populateWith(Subnet i_subnet)
+	{
+		if (i_subnet != null)
+		{
+			if (!isNullOrEmpty(i_subnet.getSubnetName()))
+				subnet_name = i_subnet.getSubnetName();
+			else
+				subnet_name = i_subnet.getSubnetId();
+			enable_dhcp = i_subnet.getEnableDHCP();
+			default_gateway = i_subnet.getGatewayIp();
+			if (!isNullOrEmpty(i_subnet.getCidr()) )
+			{
+				int idx = i_subnet.getCidr().indexOf("/");
+				if (idx != -1)
+				{
+					subnet.setIp_prefix(i_subnet.getCidr().substring(0, idx));
+					subnet.setIp_prefix_len(i_subnet.getCidr().substring(idx+1));
+				}
+			}
+			if (i_subnet.getAllocationPools() != null)
+			{
+				for (Pool pool : i_subnet.getAllocationPools())
+				{
+					if ( !isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()) )
+					{		
+						ContrailSubnetPool csp = new ContrailSubnetPool();
+						csp.populateWith(pool);
+						allocation_pools.add (csp);
+					}
+				}
+			}
+		}
+	}
+
+	@Override
+	public String toString() {
+		
+		StringBuilder buf = new StringBuilder ();
+		for (ContrailSubnetPool pool : allocation_pools)
+		{
+			 buf.append(pool.toString());
+		}
+		return "ContrailSubnet [subnet=" + subnet.toString() + " default_gateway=" + default_gateway
+				+ " enable_dhcp=" + enable_dhcp +  " addr_from_start=" + addr_from_start + " subnet_name=" + subnet_name + " allocation_pools=" + buf + " ]";
+	}
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java
new file mode 100644
index 0000000..c0a5311
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetIp.java
@@ -0,0 +1,58 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+public class ContrailSubnetIp {
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix")
+	private String ip_prefix;
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_subnet_ip_prefix_len")
+	private String ip_prefix_len; 
+
+	public ContrailSubnetIp() {
+	}
+
+	public String getIp_prefix() {
+		return ip_prefix;
+	}
+
+	public void setIp_prefix(String ip_prefix) {
+		this.ip_prefix = ip_prefix;
+	}
+
+	public String getIp_prefix_len() {
+		return ip_prefix_len;
+	}
+
+	public void setIp_prefix_len(String ip_prefix_len) {
+		this.ip_prefix_len = ip_prefix_len;
+	}
+
+	@Override
+	public String toString() {
+		return "ContrailSubnetIp [ip_prefix=" + ip_prefix + ", ip_prefix_len=" + ip_prefix_len + "]";
+	}
+
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java
new file mode 100644
index 0000000..5b40ba2
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/ContrailSubnetPool.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import org.openecomp.mso.openstack.beans.Pool;
+import org.codehaus.jackson.annotate.JsonProperty;
+public class ContrailSubnetPool {
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_start")
+	private String start;
+	
+	@JsonProperty("network_ipam_refs_data_ipam_subnets_allocation_pools_end")
+	private String end;
+
+	public ContrailSubnetPool() {
+	}
+
+	public String getStart() {
+		return start;
+	}
+
+	public void setStart(String start) {
+		this.start = start;
+	}
+
+	public String getEnd() {
+		return end;
+	}
+
+	public void setEnd(String end) {
+		this.end = end;
+	}
+	
+	public void populateWith(Pool pool)
+	{
+		if (pool != null)
+		{
+			start = pool.getStart();
+			end = pool.getEnd();
+		}
+	}
+
+	@Override
+	public String toString() {
+		return "ContrailSubnetPool [start=" + start + ", end=" + end + "]";
+	}
+	
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java
new file mode 100644
index 0000000..2767baf
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/HealthCheckHandler.java
@@ -0,0 +1,67 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import javax.ws.rs.GET;
+import javax.ws.rs.HEAD;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.Response;
+
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.HealthCheckUtils;
+import org.openecomp.mso.utils.UUIDChecker;
+
+
+@Path("/")
+	public class HealthCheckHandler {
+		
+		private static MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA);
+		private static final String MSO_PROP_NETWORK_ADAPTER = "MSO_PROP_NETWORK_ADAPTER";
+
+	    @HEAD
+	    @GET
+	    @Path("/healthcheck")
+	    @Produces("text/html")
+	    public Response healthcheck (@QueryParam("requestId") String requestId) {
+			long startTime = System.currentTimeMillis ();
+			MsoLogger.setServiceName ("Healthcheck");
+			UUIDChecker.verifyOldUUID(requestId, msoLogger);
+			HealthCheckUtils healthCheck = new HealthCheckUtils ();
+			if (!healthCheck.siteStatusCheck(msoLogger, startTime)) {
+				return HealthCheckUtils.HEALTH_CHECK_NOK_RESPONSE;
+			}
+
+			if (!healthCheck.configFileCheck(msoLogger, startTime, MSO_PROP_NETWORK_ADAPTER)) {
+				return HealthCheckUtils.NOT_STARTED_RESPONSE;
+			}
+
+			if (!healthCheck.catalogDBCheck (msoLogger, startTime)) {
+				return HealthCheckUtils.NOT_STARTED_RESPONSE;
+			}
+			msoLogger.debug("healthcheck - Successful");
+			return HealthCheckUtils.HEALTH_CHECK_RESPONSE;
+	    }
+
+
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java
new file mode 100644
index 0000000..4960877
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapter.java
@@ -0,0 +1,216 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import java.util.List;
+import java.util.Map;
+
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebParam.Mode;
+import javax.jws.WebService;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.ws.Holder;
+
+import org.openecomp.mso.adapters.network.exceptions.NetworkException;
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+import org.openecomp.mso.openstack.beans.NetworkStatus;
+import org.openecomp.mso.openstack.beans.Subnet;
+
+@WebService (name="NetworkAdapter", targetNamespace="http://com.att.mso/network")
+public interface MsoNetworkAdapter
+{
+	// TODO:  Rename all of these to include Vlan in the service name?  At least for the
+	// create and update calls, since they are specific to VLAN-based provider networks.
+
+	/**
+	 * This is the "Create Network" Web Service Endpoint definition.
+	 */
+	@WebMethod
+	public void createNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+							@WebParam(name="physicalNetworkName") String physicalNetworkName,
+							@WebParam(name="vlans") List<Integer> vlans,
+							@WebParam(name="failIfExists") Boolean failIfExists,
+							@WebParam(name="backout") Boolean backout,
+							@WebParam(name="subnets") List<Subnet> subnets,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId,
+							@WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+
+	@WebMethod
+	public void createNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+							@WebParam(name="routeTargets") List<String> routeTargets,
+							@WebParam(name="shared") String shared,
+							@WebParam(name="external") String external,
+							@WebParam(name="failIfExists") Boolean failIfExists,
+							@WebParam(name="backout") Boolean backout,
+							@WebParam(name="subnets") List<Subnet> subnets,
+							@WebParam(name="policyFqdns") List<String> policyFqdns,
+							@WebParam(name="routeTableFqdns") List<String> routeTableFqdns,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId,
+							@WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId,
+							@WebParam(name="networkFqdn", mode=Mode.OUT) Holder<String> networkFqdn,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+
+	/**
+	 * This is the "Update VLANs" Web Service Endpoint definition.
+	 * This webservice replaces the set of VLANs on a network.
+	 */
+	@WebMethod
+	public void updateNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+							@WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName,
+							@WebParam(name="vlans") @XmlElement(required=true) List<Integer> vlans,
+							@WebParam(name="subnets") List<Subnet> subnets,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+
+	@WebMethod
+	public void updateNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+							@WebParam(name="routeTargets") List<String> routeTargets,
+							@WebParam(name="shared") String shared,
+							@WebParam(name="external") String external,
+							@WebParam(name="subnets") List<Subnet> subnets,
+							@WebParam(name="policyFqdns") List<String> policyFqdns,
+							@WebParam(name="routeTableFqdns") List<String> routeTableFqdns,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+
+	/**
+	 * TODO:
+	 * This is the "Add VLAN" Web Service Endpoint definition.
+	 * This webservice adds a VLAN to a network.
+	 * This service assumes that PO supports querying the current vlans in real time.
+	 * Otherwise, the caller must have the complete list and should use updateVlans instead.
+	@WebMethod
+	public void addVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName,
+							@WebParam(name="vlan") @XmlElement(required=true) Integer vlan,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+	 */
+
+	/**
+	 * TODO:
+	 * This is the "Remove VLAN" Web Service Endpoint definition.
+	 * This webservice removes a VLAN from a network.
+	 * This service assumes that PO supports querying the current vlans in real time.
+	 * Otherwise, the caller must have the complete list and should use updateVlans instead.
+	 *
+	 * This service returns an indicator (noMoreVLans) if the VLAN that was removed was
+	 * the last one on the network.
+	 *
+	 * It is not clear that Rollback will work for delete.  The network can be
+	 * recreated from the NetworkRollback object, but the network ID (and stack ID
+	 * for Heat-based orchestration) will be different.  The caller will need to know
+	 * to update these identifiers in the inventory DB (A&AI).
+	@WebMethod
+	public void removeVlan (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName,
+							@WebParam(name="vlan") @XmlElement(required=true) Integer vlan,
+							@WebParam(name="noMoreVlans", mode=Mode.OUT) Holder<Boolean> noMoreVlans,
+							@WebParam(name="rollback", mode=Mode.OUT) Holder<NetworkRollback> rollback )
+		throws NetworkException;
+	 */
+
+	/**
+	 * This is the "Query Network" Web Service Endpoint definition.
+	 * TODO: Should this just return the NetworkInfo complete structure?
+	 */
+	@WebMethod
+	public void queryNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="networkExists", mode=Mode.OUT) Holder<Boolean> networkExists,
+							@WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId,
+							@WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId,
+							@WebParam(name="status", mode=Mode.OUT) Holder<NetworkStatus> status,
+							@WebParam(name="vlans", mode=Mode.OUT) Holder<List<Integer>> vlans,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap)
+		throws NetworkException;
+
+	@WebMethod
+	public void queryNetworkContrail (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="networkExists", mode=Mode.OUT) Holder<Boolean> networkExists,
+							@WebParam(name="networkId", mode=Mode.OUT) Holder<String> networkId,
+							@WebParam(name="neutronNetworkId", mode=Mode.OUT) Holder<String> neutronNetworkId,
+							@WebParam(name="status", mode=Mode.OUT) Holder<NetworkStatus> status,
+							@WebParam(name="routeTargets", mode=Mode.OUT) Holder<List<String>> routeTargets,
+							@WebParam(name="subnetIdMap", mode=Mode.OUT) Holder<Map<String, String>> subnetIdMap)
+		throws NetworkException;
+
+	/**
+	 * This is the "Delete Network" Web Service endpoint definition.
+	 */
+	@WebMethod
+	public void deleteNetwork (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="networkDeleted", mode=Mode.OUT) Holder<Boolean> networkDeleted)
+		throws NetworkException;
+
+	/**
+	 * This is the "Rollback Network" Web Service endpoint definition.
+	 */
+	@WebMethod
+	public void rollbackNetwork (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback rollback)
+		throws NetworkException;
+
+	@WebMethod
+	public void healthCheck ();
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java
new file mode 100644
index 0000000..e79ba12
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsync.java
@@ -0,0 +1,103 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import javax.jws.Oneway;
+import javax.jws.WebMethod;
+import javax.jws.WebParam;
+import javax.jws.WebService;
+import javax.xml.bind.annotation.XmlElement;
+
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.openstack.beans.Subnet;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+
+import java.util.List;
+/**
+ * This webservice defines the Asynchronous versions of NETWORK adapter calls.
+ * The notification messages for final responses are documented elsewhere
+ * (by the client service WSDL).
+ *
+ */
+@WebService (name="NetworkAdapterAsync", targetNamespace="http://com.att.mso/networkA")
+public interface MsoNetworkAdapterAsync
+{
+	/**
+	 * This is the "Create NETWORK" Web Service Endpoint definition.
+	 */
+	@WebMethod
+	@Oneway
+	public void createNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+							@WebParam(name="physicalNetworkName") String physicalNetworkName,
+							@WebParam(name="vlans") List<Integer> vlans,
+							@WebParam(name="failIfExists") Boolean failIfExists,
+							@WebParam(name="backout") Boolean backout,
+							@WebParam(name="subnets") List<Subnet> subnets,
+							@WebParam(name="messageId") @XmlElement(required=true) String messageId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl );
+	
+	@WebMethod
+	@Oneway
+	public void updateNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+						@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+						@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+						@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+						@WebParam(name="networkName") @XmlElement(required=true) String networkName,
+						@WebParam(name="physicalNetworkName") @XmlElement(required=true) String physicalNetworkName,
+						@WebParam(name="vlans") @XmlElement(required=true) List<Integer> vlans,
+						@WebParam(name="subnets") List<Subnet> subnets,
+						@WebParam(name="messageId") @XmlElement(required=true) String messageId,
+						@WebParam(name="request") MsoRequest msoRequest,
+						@WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl );
+
+	@WebMethod
+	@Oneway
+	public void queryNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkNameOrId") @XmlElement(required=true) String networkNameOrId,
+							@WebParam(name="messageId") @XmlElement(required=true) String messageId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl );
+
+	@WebMethod
+	@Oneway
+	public void deleteNetworkA (@WebParam(name="cloudSiteId") @XmlElement(required=true) String cloudSiteId,
+							@WebParam(name="tenantId") @XmlElement(required=true) String tenantId,
+							@WebParam(name="networkType") @XmlElement(required=true) String networkType,
+							@WebParam(name="networkId") @XmlElement(required=true) String networkId,
+							@WebParam(name="messageId") @XmlElement(required=true) String messageId,
+							@WebParam(name="request") MsoRequest msoRequest,
+							@WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl );
+
+	@WebMethod
+	@Oneway
+	public void rollbackNetworkA (@WebParam(name="rollback") @XmlElement(required=true) NetworkRollback rollback,
+						@WebParam(name="messageId") @XmlElement(required=true) String messageId,
+						@WebParam(name="notificationUrl") @XmlElement(required=true) String notificationUrl );
+	
+	@WebMethod
+	public void healthCheckA ();
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java
new file mode 100644
index 0000000..75cbc63
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterAsyncImpl.java
@@ -0,0 +1,679 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jws.WebService;
+import javax.xml.bind.DatatypeConverter;
+import javax.xml.namespace.QName;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.Holder;
+import javax.xml.ws.handler.MessageContext;
+
+import org.openecomp.mso.adapters.network.async.client.CreateNetworkNotification;
+import org.openecomp.mso.adapters.network.async.client.MsoExceptionCategory;
+import org.openecomp.mso.adapters.network.async.client.NetworkAdapterNotify;
+import org.openecomp.mso.adapters.network.async.client.NetworkAdapterNotify_Service;
+import org.openecomp.mso.adapters.network.async.client.QueryNetworkNotification;
+import org.openecomp.mso.adapters.network.async.client.UpdateNetworkNotification;
+import org.openecomp.mso.adapters.network.exceptions.NetworkException;
+import org.openecomp.mso.cloud.CloudConfigFactory;
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoAlarmLogger;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+import org.openecomp.mso.openstack.beans.NetworkStatus;
+import org.openecomp.mso.openstack.beans.Subnet;
+import org.openecomp.mso.properties.MsoPropertiesFactory;
+
+
+@WebService(serviceName = "NetworkAdapterAsync", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapterAsync", targetNamespace = "http://com.att.mso/networkA")
+public class MsoNetworkAdapterAsyncImpl implements MsoNetworkAdapterAsync {
+
+	MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
+
+	CloudConfigFactory cloudConfigFactory=new CloudConfigFactory();
+
+	public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
+    private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+    private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
+    private static final String BPEL_AUTH_PROP = "org.openecomp.mso.adapters.network.bpelauth";
+    private static final String ENCRYPTION_KEY = "aa3871669d893c7fb8abbcda31b88b4f";
+    /**
+     * Health Check web method. Does nothing but return to show the adapter is deployed.
+     */
+    @Override
+    public void healthCheckA () {
+        LOGGER.debug ("Health check call in Network Adapter");
+    }
+
+    /**
+     * This is the "Create Network" web service implementation.
+     * It will create a new Network of the requested type in the specified cloud
+     * and tenant. The tenant must exist at the time this service is called.
+     *
+     * If a network with the same name already exists, this can be considered a
+     * success or failure, depending on the value of the 'failIfExists' parameter.
+     *
+     * There will be a pre-defined set of network types defined in the MSO Catalog.
+     * All such networks will have a similar configuration, based on the allowable
+     * Openstack networking definitions. This includes basic networks, provider
+     * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
+     *
+     * Initially, all provider networks must be "vlan" type, and multiple segments in
+     * a multi-provider network must be multiple VLANs on the same physical network.
+     *
+     * This service supports two modes of Network creation/update:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition. All Heat-based templates must support some subset of
+     * the same input parameters: network_name, physical_network, vlan(s).
+     *
+     * The method returns the network ID and a NetworkRollback object. This latter
+     * object can be passed as-is to the rollbackNetwork operation to undo everything
+     * that was created. This is useful if a network is successfully created but
+     * the orchestration fails on a subsequent operation.
+     */
+    @Override
+    public void createNetworkA (String cloudSiteId,
+                                String tenantId,
+                                String networkType,
+                                String networkName,
+                                String physicalNetworkName,
+                                List <Integer> vlans,
+                                Boolean failIfExists,
+                                Boolean backout,
+                                List <Subnet> subnets,
+                                String messageId,
+                                MsoRequest msoRequest,
+                                String notificationUrl) {
+        String error;
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+        MsoLogger.setLogContext (msoRequest);
+        MsoLogger.setServiceName ("CreateNetworkA");
+        LOGGER.debug ("Async Create Network: " + networkName
+                                      + " of type "
+                                      + networkType
+                                      + " in "
+                                      + cloudSiteId
+                                      + "/"
+                                      + tenantId);
+
+        // Use the synchronous method to perform the actual Create
+        MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory);
+
+        // Synchronous Web Service Outputs
+        Holder <String> networkId = new Holder <String> ();
+        Holder <String> neutronNetworkId = new Holder <String> ();
+        Holder <NetworkRollback> networkRollback = new Holder <NetworkRollback> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> ();
+
+        try {
+            networkAdapter.createNetwork (cloudSiteId,
+                                          tenantId,
+                                          networkType,
+                                          networkName,
+                                          physicalNetworkName,
+                                          vlans,
+                                          failIfExists,
+                                          backout,
+                                          subnets,
+                                          msoRequest,
+                                          networkId,
+                                          neutronNetworkId,
+                                          subnetIdMap,
+                                          networkRollback);
+        } catch (NetworkException e) {
+            LOGGER.debug ("Got a NetworkException on createNetwork: ", e);
+            MsoExceptionCategory exCat = null;
+            String eMsg = null;
+            try {
+                eMsg = e.getFaultInfo ().getMessage ();
+                exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ());
+            } catch (Exception e1) {
+                LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1);
+            }
+            // Build and send Asynchronous error response
+            try {
+                NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+                notifyPort.createNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null);
+            } catch (Exception e1) {
+                error = "Error sending createNetwork notification " + e1.getMessage ();
+                LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1);
+                alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+            }
+            return;
+        }
+        LOGGER.debug ("Async Create Network:Name " + networkName + " physicalNetworkName:" + physicalNetworkName);
+        // Build and send Asynchronous response
+        try {
+            NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+            notifyPort.createNetworkNotification (messageId,
+                                                  true,
+                                                  null,
+                                                  null,
+                                                  networkId.value,
+                                                  neutronNetworkId.value,
+                                                  copyCreateSubnetIdMap (subnetIdMap),
+                                                  copyNrb (networkRollback));
+        } catch (Exception e) {
+            error = "Error sending createNetwork notification " + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+        }
+        return;
+    }
+
+    /**
+     * This is the "Update Network" web service implementation.
+     * It will update an existing Network of the requested type in the specified cloud
+     * and tenant. The typical use will be to replace the VLANs with the supplied
+     * list (to add or remove a VLAN), but other properties may be updated as well.
+     *
+     * There will be a pre-defined set of network types defined in the MSO Catalog.
+     * All such networks will have a similar configuration, based on the allowable
+     * Openstack networking definitions. This includes basic networks, provider
+     * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
+     *
+     * Initially, all provider networks must currently be "vlan" type, and multi-provider
+     * networks must be multiple VLANs on the same physical network.
+     *
+     * This service supports two modes of Network update:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition. All Heat-based templates must support some subset of
+     * the same input parameters: network_name, physical_network, vlan, segments.
+     *
+     * The method returns a NetworkRollback object. This object can be passed
+     * as-is to the rollbackNetwork operation to undo everything that was updated.
+     * This is useful if a network is successfully updated but orchestration
+     * fails on a subsequent operation.
+     */
+    @Override
+    public void updateNetworkA (String cloudSiteId,
+                                String tenantId,
+                                String networkType,
+                                String networkId,
+                                String networkName,
+                                String physicalNetworkName,
+                                List <Integer> vlans,
+                                List <Subnet> subnets,
+                                String messageId,
+                                MsoRequest msoRequest,
+                                String notificationUrl) {
+        String error;
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+        String serviceName = "UpdateNetworkA";
+        MsoLogger.setServiceName (serviceName);
+        MsoLogger.setLogContext (msoRequest);
+        LOGGER.debug ("Async Update Network: " + networkId
+                      + " of type "
+                      + networkType
+                      + "in "
+                      + cloudSiteId
+                      + "/"
+                      + tenantId);
+
+        // Use the synchronous method to perform the actual Create
+        MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory);
+
+        // Synchronous Web Service Outputs
+        Holder <NetworkRollback> networkRollback = new Holder <NetworkRollback> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> ();
+
+        try {
+            networkAdapter.updateNetwork (cloudSiteId,
+                                          tenantId,
+                                          networkType,
+                                          networkId,
+                                          networkName,
+                                          physicalNetworkName,
+                                          vlans,
+                                          subnets,
+                                          msoRequest,
+                                          subnetIdMap,
+                                          networkRollback);
+            MsoLogger.setServiceName (serviceName);
+        } catch (NetworkException e) {
+        	MsoLogger.setServiceName (serviceName);
+            LOGGER.debug ("Got a NetworkException on updateNetwork: ", e);
+            MsoExceptionCategory exCat = null;
+            String eMsg = null;
+            try {
+                eMsg = e.getFaultInfo ().getMessage ();
+                exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ());
+            } catch (Exception e1) {
+                LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1);
+            }
+            // Build and send Asynchronous error response
+            try {
+                NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+                notifyPort.updateNetworkNotification (messageId, false, exCat, eMsg, null, copyNrb (networkRollback));
+            } catch (Exception e1) {
+                error = "Error sending updateNetwork notification " + e1.getMessage ();
+                LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNetwork notification", e1);
+                alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+            }
+            return;
+        }
+        LOGGER.debug ("Async Update Network:Name " + networkName + " NetworkId:" + networkId);
+        // Build and send Asynchronous response
+        try {
+            NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+            notifyPort.updateNetworkNotification (messageId,
+                                                  true,
+                                                  null,
+                                                  null,
+                                                  copyUpdateSubnetIdMap (subnetIdMap),
+                                                  copyNrb (networkRollback));
+        } catch (Exception e) {
+            error = "Error sending updateNotification request" + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending updateNotification request", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+        }
+        return;
+    }
+
+    /**
+     * This is the queryNetwork method. It returns the existence and status of
+     * the specified network, along with its Neutron UUID and list of VLANs.
+     * This method attempts to find the network using both Heat and Neutron.
+     * Heat stacks are first searched based on the provided network name/id.
+     * If none is found, the Neutron is directly queried.
+     */
+    @Override
+    public void queryNetworkA (String cloudSiteId,
+                               String tenantId,
+                               String networkNameOrId,
+                               String messageId,
+                               MsoRequest msoRequest,
+                               String notificationUrl) {
+        String error;
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+        MsoLogger.setLogContext (msoRequest);
+        String serviceName = "QueryNetworkA";
+        MsoLogger.setServiceName (serviceName);
+        LOGGER.debug ("Async Query Network " + networkNameOrId + " in " + cloudSiteId + "/" + tenantId);
+
+        // Use the synchronous method to perform the actual Create
+        MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory);
+
+        // Synchronous Web Service Outputs
+        Holder <Boolean> networkExists = new Holder <Boolean> ();
+        Holder <String> networkId = new Holder <String> ();
+        Holder <String> neutronNetworkId = new Holder <String> ();
+        Holder <NetworkStatus> status = new Holder <NetworkStatus> ();
+        Holder <List <Integer>> vlans = new Holder <List <Integer>> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <Map <String, String>> ();
+
+        try {
+            networkAdapter.queryNetwork (cloudSiteId,
+                                         tenantId,
+                                         networkNameOrId,
+                                         msoRequest,
+                                         networkExists,
+                                         networkId,
+                                         neutronNetworkId,
+                                         status,
+                                         vlans,
+                                         subnetIdMap);
+            MsoLogger.setServiceName (serviceName);
+        } catch (NetworkException e) {
+        	MsoLogger.setServiceName (serviceName);
+            LOGGER.debug ("Got a NetworkException on createNetwork: ", e);
+            MsoExceptionCategory exCat = null;
+            String eMsg = null;
+            try {
+                eMsg = e.getFaultInfo ().getMessage ();
+                exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ());
+            } catch (Exception e1) {
+                LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1);
+            }
+            // Build and send Asynchronous error response
+            try {
+                NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+                notifyPort.queryNetworkNotification (messageId, false, exCat, eMsg, null, null, null, null, null, null);
+            } catch (Exception e1) {
+                error = "Error sending createNetwork notification " + e1.getMessage ();
+                LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1);
+                alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+            }
+            return;
+        }
+        LOGGER.debug ("Async Query Network:NameOrId " + networkNameOrId + " tenantId:" + tenantId);
+        // Build and send Asynchronous response
+        try {
+            NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+            org.openecomp.mso.adapters.network.async.client.NetworkStatus networkS = org.openecomp.mso.adapters.network.async.client.NetworkStatus.fromValue (status.value.name ());
+            notifyPort.queryNetworkNotification (messageId,
+                                                 true,
+                                                 null,
+                                                 null,
+                                                 networkExists.value,
+                                                 networkId.value,
+                                                 neutronNetworkId.value,
+                                                 networkS,
+                                                 vlans.value,
+                                                 copyQuerySubnetIdMap (subnetIdMap));
+        } catch (Exception e) {
+            error = "Error sending createNetwork notification " + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+        }
+        return;
+    }
+
+    /**
+     * This is the "Delete Network" web service implementation.
+     * It will delete a Network in the specified cloud and tenant.
+     *
+     * If the network is not found, it is treated as a success.
+     *
+     * This service supports two modes of Network creation/update/delete:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition.
+     *
+     * For Heat-based orchestration, the networkId should be the stack ID.
+     * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
+     *
+     * The method returns nothing on success. Rollback is not possible for delete
+     * commands, so any failure on delete will require manual fallout in the client.
+     */
+    @Override
+    public void deleteNetworkA (String cloudSiteId,
+                                String tenantId,
+                                String networkType,
+                                String networkId,
+                                String messageId,
+                                MsoRequest msoRequest,
+                                String notificationUrl) {
+        String error;
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+        MsoLogger.setLogContext (msoRequest);
+        String serviceName = "DeleteNetworkA";
+        MsoLogger.setServiceName (serviceName);
+        LOGGER.debug ("Async Delete Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
+
+        // Use the synchronous method to perform the actual Create
+        MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory);
+
+        // Synchronous Web Service Outputs
+        Holder <Boolean> networkDeleted = new Holder <Boolean> ();
+
+        try {
+            networkAdapter.deleteNetwork (cloudSiteId, tenantId, networkType, networkId, msoRequest, networkDeleted);
+            MsoLogger.setServiceName (serviceName);
+        } catch (NetworkException e) {
+        	MsoLogger.setServiceName (serviceName);
+            LOGGER.debug ("Got a NetworkException on createNetwork: ", e);
+            MsoExceptionCategory exCat = null;
+            String eMsg = null;
+            try {
+                eMsg = e.getFaultInfo ().getMessage ();
+                exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ());
+            } catch (Exception e1) {
+                LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - fault info", e1);
+            }
+            // Build and send Asynchronous error response
+            try {
+                NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+                notifyPort.deleteNetworkNotification (messageId, false, exCat, eMsg, null);
+            } catch (Exception e1) {
+                error = "Error sending createNetwork notification " + e1.getMessage ();
+                LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending createNetwork notification", e1);
+                alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+            }
+            return;
+        }
+        LOGGER.debug ("Async Delete NetworkId: " + networkId + " tenantId:" + tenantId);
+        // Build and send Asynchronous response
+        try {
+            NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+            notifyPort.deleteNetworkNotification (messageId, true, null, null, networkDeleted.value);
+        } catch (Exception e) {
+            error = "Error sending deleteNetwork notification " + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception sending deleteNetwork notification", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+        }
+        return;
+    }
+
+    /**
+     * This web service endpoint will rollback a previous Create VNF operation.
+     * A rollback object is returned to the client in a successful creation
+     * response. The client can pass that object as-is back to the rollbackNetwork
+     * operation to undo the creation.
+     *
+     * The rollback includes removing the VNF and deleting the tenant if the
+     * tenant did not exist prior to the VNF creation.
+     */
+    @Override
+    public void rollbackNetworkA (NetworkRollback rollback, String messageId, String notificationUrl) {
+        String error;
+        String serviceName = "RollbackNetworkA";
+        MsoLogger.setServiceName (serviceName);
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+        // rollback may be null (e.g. if network already existed when Create was called)
+        if (rollback == null) {
+            LOGGER.warn (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.SchemaError, "Rollback is null");
+            return;
+        }
+
+        MsoLogger.setLogContext (rollback.getMsoRequest ());
+        LOGGER.info (MessageEnum.RA_ASYNC_ROLLBACK, rollback.getNetworkStackId (), "", "");
+        // Use the synchronous method to perform the actual Create
+        MsoNetworkAdapter networkAdapter = new MsoNetworkAdapterImpl (msoPropertiesFactory,cloudConfigFactory);
+
+        try {
+            networkAdapter.rollbackNetwork (rollback);
+            MsoLogger.setServiceName (serviceName);
+        } catch (NetworkException e) {
+        	MsoLogger.setServiceName (serviceName);
+            LOGGER.debug ("Got a NetworkException on rollbackNetwork: ", e);
+            // Build and send Asynchronous error response
+            MsoExceptionCategory exCat = null;
+            String eMsg = null;
+            try {
+                eMsg = e.getFaultInfo ().getMessage ();
+                exCat = MsoExceptionCategory.fromValue (e.getFaultInfo ().getCategory ().name ());
+            } catch (Exception e1) {
+                LOGGER.error (MessageEnum.RA_FAULT_INFO_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in get fault info", e1);
+            }
+            // Build and send Asynchronous error response
+            try {
+                NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+                notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), false, exCat, eMsg);
+            } catch (Exception e1) {
+                error = "Error sending createNetwork notification " + e1.getMessage ();
+                LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending createNetwork notification ", e1);
+                alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+            }
+            return;
+        }
+        LOGGER.debug ("Async Rollback NetworkId: " + rollback.getNetworkStackId () + " tenantId:" + rollback.getTenantId ());
+        // Build and send Asynchronous response
+        try {
+            NetworkAdapterNotify notifyPort = getNotifyEP (notificationUrl);
+            notifyPort.rollbackNetworkNotification (rollback.getMsoRequest ().getRequestId (), true, null, null);
+        } catch (Exception e) {
+            error = "Error sending rollbackNetwork notification " + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_CREATE_NETWORK_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception in sending rollbackNetwork notification", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error);
+        }
+        return;
+    }
+
+    private org.openecomp.mso.adapters.network.async.client.NetworkRollback copyNrb (Holder <NetworkRollback> hNrb) {
+        org.openecomp.mso.adapters.network.async.client.NetworkRollback cnrb = new org.openecomp.mso.adapters.network.async.client.NetworkRollback ();
+
+        if (hNrb != null && hNrb.value != null) {
+            org.openecomp.mso.adapters.network.async.client.MsoRequest cmr = new org.openecomp.mso.adapters.network.async.client.MsoRequest ();
+
+            cnrb.setCloudId (hNrb.value.getCloudId ());
+            cmr.setRequestId (hNrb.value.getMsoRequest ().getRequestId ());
+            cmr.setServiceInstanceId (hNrb.value.getMsoRequest ().getServiceInstanceId ());
+            cnrb.setMsoRequest (cmr);
+            cnrb.setNetworkId (hNrb.value.getNetworkId ());
+            cnrb.setNetworkStackId (hNrb.value.getNetworkStackId ());
+            cnrb.setNeutronNetworkId (hNrb.value.getNeutronNetworkId ());
+            cnrb.setTenantId (hNrb.value.getTenantId ());
+            cnrb.setNetworkType (hNrb.value.getNetworkType ());
+            cnrb.setNetworkCreated (hNrb.value.getNetworkCreated ());
+            cnrb.setNetworkName (hNrb.value.getNetworkName ());
+            cnrb.setPhysicalNetwork (hNrb.value.getPhysicalNetwork ());
+            List <Integer> vlansc = cnrb.getVlans ();
+            List <Integer> vlansh = hNrb.value.getVlans ();
+            if (vlansh != null) {
+                vlansc.addAll (vlansh);
+            }
+        }
+        return cnrb;
+    }
+
+    private NetworkAdapterNotify getNotifyEP (String notificationUrl) {
+
+        URL warWsdlLoc = null;
+        try {
+            warWsdlLoc = Thread.currentThread ().getContextClassLoader ().getResource ("NetworkAdapterNotify.wsdl");
+        } catch (Exception e) {
+            LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "Exception - WSDL not found", e);
+        }
+        if (warWsdlLoc == null) {
+            LOGGER.error (MessageEnum.RA_WSDL_NOT_FOUND, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.DataError, "WSDL not found");
+        } else {
+            try {
+                LOGGER.debug ("NetworkAdpaterNotify.wsdl location:" + warWsdlLoc.toURI ().toString ());
+            } catch (Exception e) {
+                LOGGER.error (MessageEnum.RA_WSDL_URL_CONVENTION_EXC, "NetworkAdpaterNotify.wsdl", "", "", MsoLogger.ErrorCode.SchemaError, "Exception - WSDL URL convention", e);
+            }
+        }
+
+        NetworkAdapterNotify_Service notifySvc = new NetworkAdapterNotify_Service (warWsdlLoc,
+                                                                                   new QName ("http://com.att.mso/networkNotify",
+                                                                                              "networkAdapterNotify"));
+
+        NetworkAdapterNotify notifyPort = notifySvc.getMsoNetworkAdapterAsyncImplPort ();
+
+        BindingProvider bp = (BindingProvider) notifyPort;
+
+        URL epUrl = null;
+        try {
+            epUrl = new URL (notificationUrl);
+        } catch (MalformedURLException e1) {
+            LOGGER.error (MessageEnum.RA_INIT_NOTIF_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - init notification", e1);
+        }
+
+        LOGGER.debug ("Notification Endpoint URL: " + epUrl.toExternalForm ());
+
+        bp.getRequestContext ().put (BindingProvider.ENDPOINT_ADDRESS_PROPERTY, epUrl.toExternalForm ());
+
+        // authentication
+        try {
+            Map <String, Object> reqCtx = bp.getRequestContext ();
+            Map <String, List <String>> headers = new HashMap <String, List <String>> ();
+
+            String userCredentials = msoPropertiesFactory.getMsoJavaProperties (MSO_PROP_NETWORK_ADAPTER).getEncryptedProperty (BPEL_AUTH_PROP,
+                                                                                             "",
+                                                                                          ENCRYPTION_KEY);
+
+            String basicAuth = "Basic " + DatatypeConverter.printBase64Binary (userCredentials.getBytes ());
+            reqCtx.put (MessageContext.HTTP_REQUEST_HEADERS, headers);
+            headers.put ("Authorization", Collections.singletonList (basicAuth));
+        } catch (Exception e) {
+            String error1 = "Unable to set authorization in callback request" + e.getMessage ();
+            LOGGER.error (MessageEnum.RA_SET_CALLBACK_AUTH_EXC, "", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to set authorization in callback request", e);
+            alarmLogger.sendAlarm ("MsoInternalError", MsoAlarmLogger.CRITICAL, error1);
+        }
+
+        return notifyPort;
+    }
+
+    private CreateNetworkNotification.SubnetIdMap copyCreateSubnetIdMap (Holder <Map <String, String>> hMap) {
+
+        CreateNetworkNotification.SubnetIdMap subnetIdMap = new CreateNetworkNotification.SubnetIdMap ();
+
+        if (hMap != null && hMap.value != null) {
+            Map <String, String> sMap = new HashMap <String, String> ();
+            sMap = hMap.value;
+            CreateNetworkNotification.SubnetIdMap.Entry entry = new CreateNetworkNotification.SubnetIdMap.Entry ();
+
+            for (String key : sMap.keySet ()) {
+                entry.setKey (key);
+                entry.setValue (sMap.get (key));
+                subnetIdMap.getEntry ().add (entry);
+            }
+        }
+        return subnetIdMap;
+    }
+
+    private UpdateNetworkNotification.SubnetIdMap copyUpdateSubnetIdMap (Holder <Map <String, String>> hMap) {
+
+        UpdateNetworkNotification.SubnetIdMap subnetIdMap = new UpdateNetworkNotification.SubnetIdMap ();
+
+        if (hMap != null && hMap.value != null) {
+            Map <String, String> sMap = new HashMap <String, String> ();
+            sMap = hMap.value;
+            UpdateNetworkNotification.SubnetIdMap.Entry entry = new UpdateNetworkNotification.SubnetIdMap.Entry ();
+
+            for (String key : sMap.keySet ()) {
+                entry.setKey (key);
+                entry.setValue (sMap.get (key));
+                subnetIdMap.getEntry ().add (entry);
+            }
+        }
+        return subnetIdMap;
+    }
+
+    private QueryNetworkNotification.SubnetIdMap copyQuerySubnetIdMap (Holder <Map <String, String>> hMap) {
+
+        QueryNetworkNotification.SubnetIdMap subnetIdMap = new QueryNetworkNotification.SubnetIdMap ();
+
+        if (hMap != null && hMap.value != null) {
+            Map <String, String> sMap = new HashMap <String, String> ();
+            sMap = hMap.value;
+            QueryNetworkNotification.SubnetIdMap.Entry entry = new QueryNetworkNotification.SubnetIdMap.Entry ();
+
+            for (String key : sMap.keySet ()) {
+                entry.setKey (key);
+                entry.setValue (sMap.get (key));
+                subnetIdMap.getEntry ().add (entry);
+            }
+        }
+        return subnetIdMap;
+    }
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java
new file mode 100644
index 0000000..97624da
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/MsoNetworkAdapterImpl.java
@@ -0,0 +1,2052 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jws.WebParam;
+import javax.jws.WebService;
+import javax.xml.ws.Holder;
+
+import org.codehaus.jackson.JsonNode;
+import org.codehaus.jackson.map.ObjectMapper;
+
+import org.openecomp.mso.adapters.network.exceptions.NetworkException;
+import org.openecomp.mso.cloud.CloudConfig;
+import org.openecomp.mso.cloud.CloudConfigFactory;
+import org.openecomp.mso.cloud.CloudSite;
+import org.openecomp.mso.db.catalog.CatalogDatabase;
+import org.openecomp.mso.db.catalog.beans.HeatTemplate;
+import org.openecomp.mso.db.catalog.beans.NetworkResource;
+import org.openecomp.mso.db.catalog.utils.MavenLikeVersioning;
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoAlarmLogger;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.beans.HeatStatus;
+import org.openecomp.mso.openstack.beans.NetworkInfo;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+import org.openecomp.mso.openstack.beans.NetworkStatus;
+import org.openecomp.mso.openstack.beans.Pool;
+import org.openecomp.mso.openstack.beans.StackInfo;
+import org.openecomp.mso.openstack.beans.Subnet;
+import org.openecomp.mso.openstack.exceptions.MsoAdapterException;
+import org.openecomp.mso.openstack.exceptions.MsoException;
+import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
+import org.openecomp.mso.openstack.utils.MsoCommonUtils;
+import org.openecomp.mso.openstack.utils.MsoHeatUtils;
+import org.openecomp.mso.openstack.utils.MsoHeatUtilsWithUpdate;
+import org.openecomp.mso.openstack.utils.MsoNeutronUtils;
+import org.openecomp.mso.openstack.utils.MsoNeutronUtils.NetworkType;
+import org.openecomp.mso.properties.MsoPropertiesException;
+import org.openecomp.mso.properties.MsoPropertiesFactory;
+
+import static org.openecomp.mso.openstack.utils.MsoCommonUtils.isNullOrEmpty;
+
+@WebService(serviceName = "NetworkAdapter", endpointInterface = "org.openecomp.mso.adapters.network.MsoNetworkAdapter", targetNamespace = "http://com.att.mso/network")
+public class MsoNetworkAdapterImpl implements MsoNetworkAdapter {
+
+	MsoPropertiesFactory msoPropertiesFactory=new MsoPropertiesFactory();
+
+	CloudConfigFactory cloudConfigFactory=new CloudConfigFactory();
+
+	private static final String AIC3_NW_PROPERTY= "org.openecomp.mso.adapters.network.aic3nw";
+	private static final String AIC3_NW="OS::ContrailV2::VirtualNetwork";
+	public static final String MSO_PROP_NETWORK_ADAPTER="MSO_PROP_NETWORK_ADAPTER";
+    private static final String VLANS = "vlans";
+    private static final String PHYSICAL_NETWORK = "physical_network";
+    private static final String UPDATE_NETWORK_CONTEXT = "UpdateNetwork";
+    private static final String NETWORK_ID = "network_id";
+    private static final String NETWORK_FQDN = "network_fqdn";
+    private static final String CREATE_NETWORK_CONTEXT = "CreateNetwork";
+    private static final String MSO_CONFIGURATION_ERROR = "MsoConfigurationError";
+    private static final String NEUTRON_MODE = "NEUTRON";
+    private static MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+    private static MsoAlarmLogger alarmLogger = new MsoAlarmLogger ();
+    protected CloudConfig cloudConfig;
+
+    /**
+     * Health Check web method. Does nothing but return to show the adapter is deployed.
+     */
+    @Override
+    public void healthCheck () {
+        LOGGER.debug ("Health check call in Network Adapter");
+    }
+
+    /**
+     * Do not use this constructor or the msoPropertiesFactory will be NULL.
+     *
+  	 * @see MsoNetworkAdapterImpl#MsoNetworkAdapterImpl(MsoPropertiesFactory)
+     */
+    public MsoNetworkAdapterImpl() {
+    }
+
+    /**
+     * This constructor MUST be used if this class if called with the new operator.
+     * @param msoPropFactory
+
+     */
+    public MsoNetworkAdapterImpl(MsoPropertiesFactory msoPropFactory,CloudConfigFactory cloudConfigFact) {
+    	this.msoPropertiesFactory = msoPropFactory;
+    	this.cloudConfigFactory=cloudConfigFact;
+    	cloudConfig = cloudConfigFactory.getCloudConfig ();
+    }
+
+    @Override
+    public void createNetwork (String cloudSiteId,
+                               String tenantId,
+                               String networkType,
+                               String networkName,
+                               String physicalNetworkName,
+                               List <Integer> vlans,
+                               Boolean failIfExists,
+                               Boolean backout,
+                               List <Subnet> subnets,
+                               MsoRequest msoRequest,
+                               Holder <String> networkId,
+                               Holder <String> neutronNetworkId,
+                               Holder <Map <String, String>> subnetIdMap,
+                               Holder <NetworkRollback> rollback) throws NetworkException {
+    	Holder <String> networkFqdn = new Holder <String> ();
+        createNetwork (cloudSiteId,
+                       tenantId,
+                       networkType,
+                       networkName,
+                       physicalNetworkName,
+                       vlans,
+                       null,
+                       null,
+                       null,
+                       failIfExists,
+                       backout,
+                       subnets,
+                       null,
+                       null,
+                       msoRequest,
+                       networkId,
+                       neutronNetworkId,
+                       networkFqdn,
+                       subnetIdMap,
+                       rollback);
+    }
+
+    @Override
+    public void createNetworkContrail (String cloudSiteId,
+                                       String tenantId,
+                                       String networkType,
+                                       String networkName,
+                                       List <String> routeTargets,
+                                       String shared,
+                                       String external,
+                                       Boolean failIfExists,
+                                       Boolean backout,
+                                       List <Subnet> subnets,
+                                       List <String> policyFqdns,
+                                       List<String> routeTableFqdns,
+                                       MsoRequest msoRequest,
+                                       Holder <String> networkId,
+                                       Holder <String> neutronNetworkId,
+                                       Holder <String> networkFqdn,
+                                       Holder <Map <String, String>> subnetIdMap,
+                                       Holder <NetworkRollback> rollback) throws NetworkException {
+        createNetwork (cloudSiteId,
+                       tenantId,
+                       networkType,
+                       networkName,
+                       null,
+                       null,
+                       routeTargets,
+                       shared,
+                       external,
+                       failIfExists,
+                       backout,
+                       subnets,
+                       policyFqdns,
+                       routeTableFqdns,
+                       msoRequest,
+                       networkId,
+                       neutronNetworkId,
+                       networkFqdn,
+                       subnetIdMap,
+                       rollback);
+    }
+
+    /**
+     * This is the "Create Network" web service implementation.
+     * It will create a new Network of the requested type in the specified cloud
+     * and tenant. The tenant must exist at the time this service is called.
+     *
+     * If a network with the same name already exists, this can be considered a
+     * success or failure, depending on the value of the 'failIfExists' parameter.
+     *
+     * There will be a pre-defined set of network types defined in the MSO Catalog.
+     * All such networks will have a similar configuration, based on the allowable
+     * Openstack networking definitions. This includes basic networks, provider
+     * networks (with a single VLAN), and multi-provider networks (one or more VLANs)
+     *
+     * Initially, all provider networks must be "vlan" type, and multiple segments in
+     * a multi-provider network must be multiple VLANs on the same physical network.
+     *
+     * This service supports two modes of Network creation/update:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition. All Heat-based templates must support some subset of
+     * the same input parameters: network_name, physical_network, vlan(s).
+     *
+     * The method returns the network ID and a NetworkRollback object. This latter
+     * object can be passed as-is to the rollbackNetwork operation to undo everything
+     * that was created. This is useful if a network is successfully created but
+     * the orchestration fails on a subsequent operation.
+     */
+
+    private void createNetwork (String cloudSiteId,
+                               String tenantId,
+                               String networkType,
+                               String networkName,
+                               String physicalNetworkName,
+                               List <Integer> vlans,
+                               List <String> routeTargets,
+                               String shared,
+                               String external,
+                               Boolean failIfExists,
+                               Boolean backout,
+                               List <Subnet> subnets,
+                               List <String> policyFqdns,
+                               List <String> routeTableFqdns,
+                               MsoRequest msoRequest,
+                               Holder <String> networkId,
+                               Holder <String> neutronNetworkId,
+                               Holder <String> networkFqdn,
+                               Holder <Map <String, String>> subnetIdMap,
+                               Holder <NetworkRollback> rollback) throws NetworkException {
+        MsoLogger.setLogContext (msoRequest);
+        MsoLogger.setServiceName ("CreateNetwork");
+
+        LOGGER.debug ("*** CREATE Network: " + networkName
+                      + " of type "
+                      + networkType
+                      + " in "
+                      + cloudSiteId
+                      + "/"
+                      + tenantId);
+
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+
+        // Build a default rollback object (no actions performed)
+        NetworkRollback networkRollback = new NetworkRollback ();
+        networkRollback.setCloudId (cloudSiteId);
+        networkRollback.setTenantId (tenantId);
+        networkRollback.setMsoRequest (msoRequest);
+
+        // tenant query is not required here.
+        // If the tenant doesn’t exist, the Heat calls will fail anyway (when the HeatUtils try to obtain a token).
+        // So this is just catching that error in a bit more obvious way up front.
+
+        cloudConfig = cloudConfigFactory.getCloudConfig ();
+        CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        if (cloudSite == null)
+        {
+        	String error = "Configuration Error. Stack " + networkName + " in "
+        			+ cloudSiteId
+        			+ "/"
+        			+ tenantId
+        			+ ": "
+        			+ " CloudSite does not exist in MSO Configuration";
+        	LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
+        	// Set the detailed error as the Exception 'message'
+        	throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+
+        try (CatalogDatabase db = getCatalogDb()) {
+            NetworkResource networkResource = networkCheck (db,
+                                                            startTime,
+                                                            networkType,
+                                                            networkName,
+                                                            physicalNetworkName,
+                                                            vlans,
+                                                            routeTargets,
+                                                            cloudSite);
+            String mode = networkResource.getOrchestrationMode ();
+            NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
+
+            if (NEUTRON_MODE.equals (mode)) {
+
+                // Use an MsoNeutronUtils for all neutron commands
+                MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
+
+                // See if the Network already exists (by name)
+                NetworkInfo netInfo = null;
+                long queryNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    netInfo = neutron.queryNetwork (networkName, tenantId, cloudSiteId);
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null);
+                } catch (MsoException me) {
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack", "OpenStack", "QueryNetwork", null);
+                    String error = "Create Network (neutron): query network " + networkName
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while querying network from OpenStack", me);
+                    me.addContext (CREATE_NETWORK_CONTEXT);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying network from OpenStack");
+                    throw new NetworkException (me);
+                }
+
+                if (netInfo != null) {
+                    // Exists. If that's OK, return success with the network ID.
+                    // Otherwise, return an exception.
+                    if (failIfExists != null && failIfExists) {
+                        String error = "Create Nework: Network " + networkName
+                                       + " already exists in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + " with ID " + netInfo.getId();
+                        LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network already exists");
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
+                        throw new NetworkException(error, MsoExceptionCategory.USERDATA);
+                    } else {
+                        // Populate the outputs from the existing network.
+                        networkId.value = netInfo.getId ();
+                        neutronNetworkId.value = netInfo.getId ();
+                        rollback.value = networkRollback; // Default rollback - no updates performed
+                        String msg = "Found Existing network, status=" + netInfo.getStatus () + " for Neutron mode";
+                        LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "", MsoLogger.ErrorCode.DataError, "Found Existing network, status=" + netInfo.getStatus ());
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, msg);
+                    }
+                    return;
+                }
+
+                long createNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    netInfo = neutron.createNetwork (cloudSiteId,
+                                                     tenantId,
+                                                     neutronNetworkType,
+                                                     networkName,
+                                                     physicalNetworkName,
+                                                     vlans);
+                    LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "CreateNetwork", null);
+                } catch (MsoException me) {
+                	me.addContext (CREATE_NETWORK_CONTEXT);
+                    LOGGER.recordMetricEvent (createNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while communicate with OpenStack", "OpenStack", "CreateNetwork", null);
+                	String error = "Create Network: type " + neutronNetworkType
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while communicate with OpenStack", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+
+                    throw new NetworkException (me);
+                }
+
+                // Note: ignoring MsoNetworkAlreadyExists because we already checked.
+
+                // If reach this point, network creation is successful.
+                // Since directly created via Neutron, networkId tracked by MSO is the same
+                // as the neutron network ID.
+                networkId.value = netInfo.getId ();
+                neutronNetworkId.value = netInfo.getId ();
+
+                networkRollback.setNetworkCreated (true);
+                networkRollback.setNetworkId (netInfo.getId ());
+                networkRollback.setNeutronNetworkId (netInfo.getId ());
+                networkRollback.setNetworkType (networkType);
+
+                LOGGER.debug ("Network " + networkName + " created, id = " + netInfo.getId ());
+            } else if ("HEAT".equals (mode)) {
+
+                // Use an MsoHeatUtils for all Heat commands
+                MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
+                
+                HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
+                if (heatTemplate == null) {
+                    String error = "Network error - undefined Heat Template. Network Type = " + networkType;
+                    LOGGER.error (MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type = " + networkType);
+                    alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
+                                                                                                     // error,
+                                                                                                     // configuration
+                                                                                                     // must be fixed
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataNotFound, error);
+                    throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
+                }
+
+                LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
+                
+                // "Fix" the template if it has CR/LF (getting this from Oracle)
+                String template = heatTemplate.getHeatTemplate ();
+                template = template.replaceAll ("\r\n", "\n");
+                
+                boolean aic3template=false;
+                String aic3nw = AIC3_NW;
+                try {
+                	aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER).getProperty(AIC3_NW_PROPERTY, AIC3_NW);
+        		} catch (MsoPropertiesException e) {
+        			String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
+        			LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to get properties", e);
+        		}
+            	
+                if (template.contains(aic3nw))
+                	aic3template = true;
+                
+                // First, look up to see if the Network already exists (by name).
+                // For HEAT orchestration of networks, the stack name will always match the network name
+                StackInfo heatStack = null;
+                long queryNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    heatStack = heat.queryStack (cloudSiteId, tenantId, networkName);
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Response successfully received from OpenStack", "OpenStack", "QueryNetwork", null);
+                } catch (MsoException me) {
+                    me.addContext (CREATE_NETWORK_CONTEXT);
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, "Exception while querying stack from OpenStack", "OpenStack", "QueryNetwork", null);
+                	String error = "Create Network (heat): query network " + networkName
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkName, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception while querying stack from OpenStack", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                if (heatStack != null && !(heatStack.getStatus () == HeatStatus.NOTFOUND)) {
+                    // Stack exists. Return success or error depending on input directive
+                    if (failIfExists != null && failIfExists) {
+                        String error = "CreateNetwork: Stack " + networkName
+                                       + " already exists in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + " as " + heatStack.getCanonicalName();
+                        LOGGER.error (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "", MsoLogger.ErrorCode.DataError, "Network already exists");
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Conflict, error);
+                        throw new NetworkException(error, MsoExceptionCategory.USERDATA);
+                    } else {
+                        // Populate the outputs from the existing stack.
+                        networkId.value = heatStack.getCanonicalName ();
+                        neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
+                        rollback.value = networkRollback; // Default rollback - no updates performed
+                        if (aic3template)
+                        {
+                        	networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
+                        }
+                        Map <String, Object> outputs = heatStack.getOutputs ();
+                        Map <String, String> sMap = new HashMap <String, String> ();
+                        if (outputs != null) {
+                        	for (String key : outputs.keySet ()) {
+                        		if (key != null && key.startsWith ("subnet")) {
+                        			if (aic3template) //one subnet_id output 
+                        			{
+                        				 Map <String, String> map = getSubnetUUId(key, outputs, subnets); 
+                        				 sMap.putAll(map);
+                        			}
+                        			else //multiples subnet_%aaid% outputs
+                        			{
+                        				String subnetUUId = (String) outputs.get(key); 
+                        				sMap.put (key.substring("subnet_id_".length()), subnetUUId);
+                        			}
+                        		}
+                        	}
+                        }
+                        subnetIdMap.value = sMap;
+                        String msg = "Found Existing network stack, status=" + heatStack.getStatus () + " for Heat mode";
+                        LOGGER.warn (MessageEnum.RA_NETWORK_ALREADY_EXIST, networkName, cloudSiteId, tenantId, "", "", MsoLogger.ErrorCode.DataError, "Found Existing network stack, status=" + heatStack.getStatus ());
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Found Existing network stack");
+                    }
+                    return;
+                }
+
+                // Ready to deploy the new Network
+                // Build the common set of HEAT template parameters
+                Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType,
+                                                                          networkName,
+                                                                          physicalNetworkName,
+                                                                          vlans,
+                                                                          routeTargets,
+                                                                          shared, 
+                                                                          external,
+                                                                          aic3template);
+
+                // Validate (and update) the input parameters against the DB definition
+                // Shouldn't happen unless DB config is wrong, since all networks use same inputs
+                // and inputs were already validated.
+                try {
+                    stackParams = heat.validateStackParams (stackParams, heatTemplate);
+                } catch (IllegalArgumentException e) {
+                    String error = "Create Network: Configuration Error: " + e.getMessage ();
+                    LOGGER.error (MessageEnum.RA_CONFIG_EXC, e.getMessage(), "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - Create Network, Configuration Error", e);
+                    alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error); // Alarm on this
+                                                                                                     // error,
+                                                                                                     // configuration
+                                                                                                     // must be fixed
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
+                    // Input parameters were not valid
+                    throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
+                }
+
+                if (subnets != null) {
+                	try {
+                		if (aic3template)
+                		{
+                			template = mergeSubnetsAIC3 (template, subnets, stackParams);
+                		}
+                		else
+                		{
+                			template = mergeSubnets (template, subnets);
+                		}
+                	} catch (MsoException me) {
+                		me.addContext (CREATE_NETWORK_CONTEXT);
+                		String error = "Create Network (heat): type " + neutronNetworkType
+                				+ " in "
+                				+ cloudSiteId
+                				+ "/"
+                				+ tenantId
+                				+ ": "
+                				+ me;
+                		LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging subnets", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                		throw new NetworkException (me);
+                	}
+                }
+
+                if (policyFqdns != null && !policyFqdns.isEmpty() && aic3template) {
+                    try {
+                        mergePolicyRefs (policyFqdns, stackParams);
+                    } catch (MsoException me) {
+                        me.addContext (CREATE_NETWORK_CONTEXT);
+                    	String error = "Create Network (heat) mergePolicyRefs type " + neutronNetworkType
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging policyRefs", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+                
+                if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
+                    try {
+                        mergeRouteTableRefs (routeTableFqdns, stackParams);
+                    } catch (MsoException me) {
+                        me.addContext (CREATE_NETWORK_CONTEXT);
+                    	String error = "Create Network (heat) mergeRouteTableRefs type " + neutronNetworkType
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception Create Network, merging routeTableRefs", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+
+                // Deploy the network stack
+                // Ignore MsoStackAlreadyExists exception because we already checked.
+                long createStackStartTime = System.currentTimeMillis ();
+                try {
+                	if (backout == null)
+                		backout = true;
+                    heatStack = heat.createStack (cloudSiteId,
+                                                  tenantId,
+                                                  networkName,
+                                                  template,
+                                                  stackParams,
+                                                  true,
+                                                  heatTemplate.getTimeoutMinutes (),
+                                                  null,
+                                                  null,
+                                                  null,
+                                                  backout.booleanValue());
+                } catch (MsoException me) {
+                    me.addContext (CREATE_NETWORK_CONTEXT);
+                	String error = "Create Network (heat): type " + neutronNetworkType
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, networkName, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception creating network", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                // Reach this point if createStack is successful.
+
+                // For Heat-based orchestration, the MSO-tracked network ID is the heat stack,
+                // and the neutronNetworkId is the network UUID returned in stack outputs.
+                networkId.value = heatStack.getCanonicalName ();
+                neutronNetworkId.value = (String) heatStack.getOutputs ().get (NETWORK_ID);
+                if (aic3template)
+                {
+                	networkFqdn.value = (String) heatStack.getOutputs().get(NETWORK_FQDN);
+                }
+                Map <String, Object> outputs = heatStack.getOutputs ();
+                Map <String, String> sMap = new HashMap <String, String> ();
+                if (outputs != null) {
+                    for (String key : outputs.keySet ()) {
+                        if (key != null && key.startsWith ("subnet")) {
+                        	if (aic3template) //one subnet output expected
+                			{
+                				 Map <String, String> map = getSubnetUUId(key, outputs, subnets); 
+                				 sMap.putAll(map);
+                			}
+                			else //multiples subnet_%aaid% outputs allowed
+                			{
+                				String subnetUUId = (String) outputs.get(key); 
+                				sMap.put (key.substring("subnet_id_".length()), subnetUUId);
+                			}
+                        }
+                    }
+                }
+                subnetIdMap.value = sMap;
+
+                rollback.value = networkRollback;
+                // Populate remaining rollback info and response parameters.
+                networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
+                networkRollback.setNeutronNetworkId ((String) heatStack.getOutputs ().get (NETWORK_ID));
+                networkRollback.setNetworkCreated (true);
+                networkRollback.setNetworkType (networkType);
+
+                LOGGER.debug ("Network " + networkName + " successfully created via HEAT");
+            }
+        }
+        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.Suc, "Successfully created network");
+        return;
+    }
+
+    @Override
+    public void updateNetwork (String cloudSiteId,
+                               String tenantId,
+                               String networkType,
+                               String networkId,
+                               String networkName,
+                               String physicalNetworkName,
+                               List <Integer> vlans,
+                               List <Subnet> subnets,
+                               MsoRequest msoRequest,
+                               Holder <Map <String, String>> subnetIdMap,
+                               Holder <NetworkRollback> rollback) throws NetworkException {
+        updateNetwork (cloudSiteId,
+                       tenantId,
+                       networkType,
+                       networkId,
+                       networkName,
+                       physicalNetworkName,
+                       vlans,
+                       null,
+                       null,
+                       null,
+                       subnets,
+                       null,
+                       null,
+                       msoRequest,
+                       subnetIdMap,
+                       rollback);
+
+    }
+
+    @Override
+    public void updateNetworkContrail (String cloudSiteId,
+                                       String tenantId,
+                                       String networkType,
+                                       String networkId,
+                                       String networkName,
+                                       List <String> routeTargets,
+                                       String shared,
+                                       String external,
+                                       List <Subnet> subnets,
+                                       List <String> policyFqdns,
+                                       List<String> routeTableFqdns,
+                                       MsoRequest msoRequest,
+                                       Holder <Map <String, String>> subnetIdMap,
+                                       Holder <NetworkRollback> rollback) throws NetworkException {
+        updateNetwork (cloudSiteId,
+                       tenantId,
+                       networkType,
+                       networkId,
+                       networkName,
+                       null,
+                       null,
+                       routeTargets,
+                       shared,
+                       external,
+                       subnets,
+                       policyFqdns,
+                       routeTableFqdns,
+                       msoRequest,
+                       subnetIdMap,
+                       rollback);
+    }
+
+    /**
+     * This is the "Update Network" web service implementation.
+     * It will update an existing Network of the requested type in the specified cloud
+     * and tenant. The typical use will be to replace the VLANs with the supplied
+     * list (to add or remove a VLAN), but other properties may be updated as well.
+     *
+     * There will be a pre-defined set of network types defined in the MSO Catalog.
+     * All such networks will have a similar configuration, based on the allowable
+     * Openstack networking definitions. This includes basic networks, provider
+     * networks (with a single VLAN), and multi-provider networks (one or more VLANs).
+     *
+     * Initially, all provider networks must currently be "vlan" type, and multi-provider
+     * networks must be multiple VLANs on the same physical network.
+     *
+     * This service supports two modes of Network update:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition. All Heat-based templates must support some subset of
+     * the same input parameters: network_name, physical_network, vlan, segments.
+     *
+     * The method returns a NetworkRollback object. This object can be passed
+     * as-is to the rollbackNetwork operation to undo everything that was updated.
+     * This is useful if a network is successfully updated but orchestration
+     * fails on a subsequent operation.
+     */
+    private void updateNetwork (String cloudSiteId,
+                               String tenantId,
+                               String networkType,
+                               String networkId,
+                               String networkName,
+                               String physicalNetworkName,
+                               List <Integer> vlans,
+                               List <String> routeTargets,
+                               String shared,
+                               String external,
+                               List <Subnet> subnets,
+                               List <String> policyFqdns,
+                               List<String> routeTableFqdns,
+                               MsoRequest msoRequest,
+                               Holder <Map <String, String>> subnetIdMap,
+                               Holder <NetworkRollback> rollback) throws NetworkException {
+        MsoLogger.setLogContext (msoRequest);
+        MsoLogger.setServiceName ("UpdateNetwork");
+        LOGGER.debug ("***UPDATE Network adapter with Network: " + networkName
+                + " of type "
+                + networkType
+                + " in "
+                + cloudSiteId
+                + "/"
+                + tenantId);
+
+
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+
+        // Build a default rollback object (no actions performed)
+        NetworkRollback networkRollback = new NetworkRollback ();
+        networkRollback.setCloudId (cloudSiteId);
+        networkRollback.setTenantId (tenantId);
+        networkRollback.setMsoRequest (msoRequest);
+
+        cloudConfig = cloudConfigFactory.getCloudConfig ();
+        CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        if (cloudSite == null) {
+        	   String error = "UpdateNetwork: Configuration Error. Stack " + networkName + " in "
+                       + cloudSiteId
+                       + "/"
+                       + tenantId
+                       + ": "
+                       + " CloudSite does not exist in MSO Configuration";
+        	   LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "CloudSite does not exist in MSO Configuration");
+               LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
+        	   // Set the detailed error as the Exception 'message'
+        	   throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+
+        try(CatalogDatabase db = getCatalogDb()) {
+            NetworkResource networkResource = networkCheck (db,
+                                                            startTime,
+                                                            networkType,
+                                                            networkName,
+                                                            physicalNetworkName,
+                                                            vlans,
+                                                            routeTargets,
+                                                            cloudSite);
+            String mode = networkResource.getOrchestrationMode ();
+            NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
+
+            // Use an MsoNeutronUtils for all Neutron commands
+            MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
+
+            if (NEUTRON_MODE.equals (mode)) {
+
+                // Verify that the Network exists
+                // For Neutron-based orchestration, the networkId is the Neutron Network UUID.
+                NetworkInfo netInfo = null;
+                long queryNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    netInfo = neutron.queryNetwork (networkId, tenantId, cloudSiteId);
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
+                } catch (MsoException me) {
+                    me.addContext (UPDATE_NETWORK_CONTEXT);
+                	String error = "Update Network (neutron): query " + networkId
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
+                    LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "QueryNetwork", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - queryNetwork", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                if (netInfo == null) {
+                    String error = "Update Nework: Network " + networkId
+                                   + " does not exist in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId;
+                    LOGGER.error (MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Network not found");
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                    // Does not exist. Throw an exception (can't update a non-existent network)
+                    throw new NetworkException(error, MsoExceptionCategory.USERDATA);
+                }
+                long updateNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    netInfo = neutron.updateNetwork (cloudSiteId,
+                                                     tenantId,
+                                                     networkId,
+                                                     neutronNetworkType,
+                                                     physicalNetworkName,
+                                                     vlans);
+                    LOGGER.recordMetricEvent (updateNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateNetwork", null);
+                } catch (MsoException me) {
+                    me.addContext (UPDATE_NETWORK_CONTEXT);
+                    String error = "Update Network (neutron): " + networkId
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "Openstack", "updateNetwork", MsoLogger.ErrorCode.DataError, "Exception - updateNetwork", me);
+                    LOGGER.recordMetricEvent (updateNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateNetwork", null);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                // Add the network ID and previously queried vlans to the rollback object
+                networkRollback.setNetworkId (netInfo.getId ());
+                networkRollback.setNeutronNetworkId (netInfo.getId ());
+                networkRollback.setNetworkType (networkType);
+                // Save previous parameters
+                networkRollback.setNetworkName (netInfo.getName ());
+                networkRollback.setPhysicalNetwork (netInfo.getProvider ());
+                networkRollback.setVlans (netInfo.getVlans ());
+
+                LOGGER.debug ("Network " + networkId + " updated, id = " + netInfo.getId ());
+            } else if ("HEAT".equals (mode)) {
+
+                // Use an MsoHeatUtils for all Heat commands
+                MsoHeatUtilsWithUpdate heat = new MsoHeatUtilsWithUpdate (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
+
+                // First, look up to see that the Network already exists.
+                // For Heat-based orchestration, the networkId is the network Stack ID.
+                StackInfo heatStack = null;
+                long queryStackStarttime = System.currentTimeMillis ();
+                try {
+                    heatStack = heat.queryStack (cloudSiteId, tenantId, networkName);
+                    LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
+                } catch (MsoException me) {
+                    me.addContext (UPDATE_NETWORK_CONTEXT);
+                    String error = "UpdateNetwork (heat): query " + networkName
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryStack", null);
+                    LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - QueryStack", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                if (heatStack == null || (heatStack.getStatus () == HeatStatus.NOTFOUND)) {
+                    String error = "UpdateNetwork: Stack " + networkName
+                                   + " does not exist in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId;
+                    LOGGER.error (MessageEnum.RA_NETWORK_NOT_FOUND, networkId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Network not found");
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                    // Network stack does not exist. Return an error
+                    throw new NetworkException(error, MsoExceptionCategory.USERDATA);
+                }
+
+                // Get the previous parameters for rollback
+                Map <String, Object> heatParams = heatStack.getParameters ();
+
+                String previousNetworkName = (String) heatParams.get ("network_name");
+                String previousPhysicalNetwork = (String) heatParams.get (PHYSICAL_NETWORK);
+
+                List <Integer> previousVlans = new ArrayList <Integer> ();
+                String vlansParam = (String) heatParams.get (VLANS);
+                if (vlansParam != null) {
+                    for (String vlan : vlansParam.split (",")) {
+                        try {
+                            previousVlans.add (Integer.parseInt (vlan));
+                        } catch (NumberFormatException e) {
+                            LOGGER.warn (MessageEnum.RA_VLAN_PARSE, networkId, vlansParam, "", "", MsoLogger.ErrorCode.DataError, "Exception - VLAN parse", e);
+                        }
+                    }
+                }
+                LOGGER.debug ("Update Stack:  Previous VLANS: " + previousVlans);
+
+                // Ready to deploy the updated Network via Heat
+
+                HeatTemplate heatTemplate = db.getHeatTemplate (networkResource.getTemplateId ());
+                if (heatTemplate == null) {
+                    String error = "Network error - undefined Heat Template. Network Type=" + networkType;
+                    LOGGER.error (MessageEnum.RA_PARAM_NOT_FOUND, "Heat Template", "Network Type", networkType, "OpenStack", "getHeatTemplate", MsoLogger.ErrorCode.DataError, "Network error - undefined Heat Template. Network Type=" + networkType);
+                    alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                    throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
+                }
+
+                LOGGER.debug ("Got HEAT Template from DB: " + heatTemplate.toString ());
+                
+                // "Fix" the template if it has CR/LF (getting this from Oracle)
+                String template = heatTemplate.getHeatTemplate ();
+                template = template.replaceAll ("\r\n", "\n");
+                
+                boolean aic3template=false;
+                String aic3nw = AIC3_NW;
+                try {
+                	aic3nw = msoPropertiesFactory.getMsoJavaProperties(MSO_PROP_NETWORK_ADAPTER).getProperty(AIC3_NW_PROPERTY, AIC3_NW);
+        		} catch (MsoPropertiesException e) {
+        			String error = "Unable to get properties:" + MSO_PROP_NETWORK_ADAPTER;
+        			LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Unable to get properties", e);
+        		}
+                if (template.contains(aic3nw))
+                	aic3template = true;
+
+                // Build the common set of HEAT template parameters
+                Map <String, Object> stackParams = populateNetworkParams (neutronNetworkType,
+                                                                          networkName,
+                                                                          physicalNetworkName,
+                                                                          vlans,
+                                                                          routeTargets,
+                                                                          shared,
+                                                                          external,
+                                                                          aic3template);
+
+                // Validate (and update) the input parameters against the DB definition
+                // Shouldn't happen unless DB config is wrong, since all networks use same inputs
+                try {
+                    stackParams = heat.validateStackParams (stackParams, heatTemplate);
+                } catch (IllegalArgumentException e) {
+                    String error = "UpdateNetwork: Configuration Error: Network Type=" + networkType;
+                    LOGGER.error (MessageEnum.RA_CONFIG_EXC, "Network Type=" + networkType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork: Configuration Error");
+                    alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.SchemaError, error);
+                    throw new NetworkException (error, MsoExceptionCategory.INTERNAL, e);
+                }
+
+                if (subnets != null) {
+                    try {
+                    	if (aic3template)
+                		{
+                			template = mergeSubnetsAIC3 (template, subnets, stackParams);
+                		}
+                		else
+                		{
+                			template = mergeSubnets (template, subnets);
+                		}
+                    } catch (MsoException me) {
+                        me.addContext (UPDATE_NETWORK_CONTEXT);
+                        String error = "Update Network (heat): type " + neutronNetworkType
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeSubnets ", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+
+                if (policyFqdns != null && aic3template) {
+                    try {
+                    	mergePolicyRefs (policyFqdns, stackParams);
+                    } catch (MsoException me) {
+                        me.addContext (UPDATE_NETWORK_CONTEXT);
+                    	String error = "UpdateNetwork (heat) mergePolicyRefs type " + neutronNetworkType
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergePolicyRefs", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+                
+                if (routeTableFqdns != null && !routeTableFqdns.isEmpty() && aic3template) {
+                    try {
+                        mergeRouteTableRefs (routeTableFqdns, stackParams);
+                    } catch (MsoException me) {
+                        me.addContext (UPDATE_NETWORK_CONTEXT);
+                    	String error = "UpdateNetwork (heat) mergeRouteTableRefs type " + neutronNetworkType
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, neutronNetworkType.toString(), cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception - UpdateNetwork mergeRouteTableRefs", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.InternalError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+                
+                // Update the network stack
+                // Ignore MsoStackNotFound exception because we already checked.
+                long updateStackStarttime = System.currentTimeMillis ();
+                try {
+                    heatStack = heat.updateStack (cloudSiteId,
+                                                  tenantId,
+                                                  networkId,
+                                                  template,
+                                                  stackParams,
+                                                  true,
+                                                  heatTemplate.getTimeoutMinutes ());
+                    LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "UpdateStack", null);
+                } catch (MsoException me) {
+                    me.addContext (UPDATE_NETWORK_CONTEXT);
+                    String error = "Update Network: " + networkId + " in " + cloudSiteId + "/" + tenantId + ": " + me;
+                    LOGGER.recordMetricEvent (updateStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "UpdateStack", null);
+                    LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - update network", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+
+                Map <String, Object> outputs = heatStack.getOutputs ();
+                Map <String, String> sMap = new HashMap <String, String> ();
+                if (outputs != null) {
+                    for (String key : outputs.keySet ()) {
+                        if (key != null && key.startsWith ("subnet")) {
+                        	if (aic3template) //one subnet output expected
+                			{
+                				 Map <String, String> map = getSubnetUUId(key, outputs, subnets); 
+                				 sMap.putAll(map);
+                			}
+                			else //multiples subnet_%aaid% outputs allowed
+                			{
+                				String subnetUUId = (String) outputs.get(key); 
+                				sMap.put (key.substring("subnet_id_".length()), subnetUUId);
+                			}
+                        }
+                    }
+                }
+                subnetIdMap.value = sMap;
+
+                // Reach this point if createStack is successful.
+                // Populate remaining rollback info and response parameters.
+                networkRollback.setNetworkStackId (heatStack.getCanonicalName ());
+                networkRollback.setNeutronNetworkId ((String) outputs.get (NETWORK_ID));
+                networkRollback.setNetworkType (networkType);
+                // Save previous parameters
+                networkRollback.setNetworkName (previousNetworkName);
+                networkRollback.setPhysicalNetwork (previousPhysicalNetwork);
+                networkRollback.setVlans (previousVlans);
+
+                rollback.value = networkRollback;
+
+                LOGGER.debug ("Network " + networkId + " successfully updated via HEAT");
+            }
+        }
+        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully updated network");
+        return;
+    }
+
+    private NetworkResource networkCheck (CatalogDatabase db,
+                                          long startTime,
+                                          String networkType,
+                                          String networkName,
+                                          String physicalNetworkName,
+                                          List <Integer> vlans,
+                                          List <String> routeTargets,
+                                          CloudSite cloudSite) throws NetworkException {
+        // Retrieve the Network Resource definition
+        NetworkResource networkResource = db.getNetworkResource (networkType);
+        if (networkResource == null) {
+            String error = "CreateNetwork: Unknown Network Type: " + networkType;
+            LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "OpenStack", "", MsoLogger.ErrorCode.DataError, "CreateNetwork: Unknown Network Type");
+
+            throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+        LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ());
+
+        String mode = networkResource.getOrchestrationMode ();
+        NetworkType neutronNetworkType = NetworkType.valueOf (networkResource.getNeutronNetworkType ());
+
+        // All Networks are orchestrated via HEAT or Neutron
+        if (!("HEAT".equals (mode) || NEUTRON_MODE.equals (mode))) {
+            String error = "CreateNetwork: Configuration Error: Network Type = " + networkType;
+            LOGGER.error (MessageEnum.RA_NETWORK_ORCHE_MODE_NOT_SUPPORT, mode, "OpenStack", "", MsoLogger.ErrorCode.DataError, "CreateNetwork: Configuration Error");
+            // Alarm on this error, configuration must be fixed
+            alarmLogger.sendAlarm (MSO_CONFIGURATION_ERROR, MsoAlarmLogger.CRITICAL, error);
+
+            throw new NetworkException (error, MsoExceptionCategory.INTERNAL);
+        }
+
+        MavenLikeVersioning aicV = new MavenLikeVersioning();
+		aicV.setVersion(cloudSite.getAic_version());
+		if ((aicV.isMoreRecentThan(networkResource.getAicVersionMin()) || aicV.isTheSameVersion(networkResource.getAicVersionMin())) // aic >= min
+				&& (aicV.isTheSameVersion(networkResource.getAicVersionMax()) || !(aicV.isMoreRecentThan(networkResource.getAicVersionMax())))) //aic <= max
+		{
+			LOGGER.debug ("Network Type:" + networkType 
+				+   " VersionMin:" + networkResource.getAicVersionMin() 
+				+	" VersionMax:" + networkResource.getAicVersionMax() 
+				+	" supported on Cloud:" + cloudSite.getId()
+				+	" with AIC_Version:" + cloudSite.getAic_version());
+		}
+		else
+		{
+			String error = "Network Type:" + networkType
+					+ " Version_Min:" + networkResource.getAicVersionMin() 
+					+ " Version_Max:" + networkResource.getAicVersionMax() 
+					+ " not supported on Cloud:" + cloudSite.getId()
+					+ " with AIC_Version:"  + cloudSite.getAic_version();
+			LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Network Type not supported on Cloud");
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
+			throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+		}
+
+
+        // Validate the Network parameters.
+        String missing = validateNetworkParams (neutronNetworkType,
+                                                networkName,
+                                                physicalNetworkName,
+                                                vlans,
+                                                routeTargets);
+        if (!missing.isEmpty ()) {
+            String error = "Create Network: Missing parameters: " + missing;
+            LOGGER.error (MessageEnum.RA_MISSING_PARAM, missing, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Create Network: Missing parameters");
+
+            throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+        return networkResource;
+    }
+
+    @Override
+    public void queryNetwork (String cloudSiteId,
+                              String tenantId,
+                              String networkNameOrId,
+                              MsoRequest msoRequest,
+                              Holder <Boolean> networkExists,
+                              Holder <String> networkId,
+                              Holder <String> neutronNetworkId,
+                              Holder <NetworkStatus> status,
+                              Holder <List <Integer>> vlans,
+                              Holder <Map <String, String>> subnetIdMap) throws NetworkException {
+        queryNetwork (cloudSiteId,
+                      tenantId,
+                      networkNameOrId,
+                      msoRequest,
+                      networkExists,
+                      networkId,
+                      neutronNetworkId,
+                      status,
+                      vlans,
+                      null,
+                      subnetIdMap);
+    }
+
+    @Override
+    public void queryNetworkContrail (String cloudSiteId,
+                                      String tenantId,
+                                      String networkNameOrId,
+                                      MsoRequest msoRequest,
+                                      Holder <Boolean> networkExists,
+                                      Holder <String> networkId,
+                                      Holder <String> neutronNetworkId,
+                                      Holder <NetworkStatus> status,
+                                      Holder <List <String>> routeTargets,
+                                      Holder <Map <String, String>> subnetIdMap) throws NetworkException {
+        queryNetwork (cloudSiteId,
+                      tenantId,
+                      networkNameOrId,
+                      msoRequest,
+                      networkExists,
+                      networkId,
+                      neutronNetworkId,
+                      status,
+                      null,
+                      routeTargets,
+                      subnetIdMap);
+    }
+
+    /**
+     * This is the queryNetwork method. It returns the existence and status of
+     * the specified network, along with its Neutron UUID and list of VLANs.
+     * This method attempts to find the network using both Heat and Neutron.
+     * Heat stacks are first searched based on the provided network name/id.
+     * If none is found, the Neutron is directly queried.
+     */
+    private void queryNetwork (String cloudSiteId,
+                              String tenantId,
+                              String networkNameOrId,
+                              MsoRequest msoRequest,
+                              Holder <Boolean> networkExists,
+                              Holder <String> networkId,
+                              Holder <String> neutronNetworkId,
+                              Holder <NetworkStatus> status,
+                              Holder <List <Integer>> vlans,
+                              Holder <List <String>> routeTargets,
+                              Holder <Map <String, String>> subnetIdMap) throws NetworkException {
+        MsoLogger.setLogContext (msoRequest);
+        MsoLogger.setServiceName ("QueryNetwork");
+        LOGGER.debug ("*** QUERY Network with Network: " + networkNameOrId
+                + " in "
+                + cloudSiteId
+                + "/"
+                + tenantId);
+
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+
+        if (isNullOrEmpty (cloudSiteId)
+            || isNullOrEmpty(tenantId)
+            || isNullOrEmpty(networkNameOrId)) {
+
+            String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
+            LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkNameOrId", "OpenStack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+            throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+
+        cloudConfig = cloudConfigFactory.getCloudConfig ();
+        CloudSite cloudSite = cloudConfig.getCloudSite (cloudSiteId);
+        if (cloudSite == null)
+        {
+        	String error = "Configuration Error. Stack " + networkNameOrId + " in "
+        			+ cloudSiteId
+        			+ "/"
+        			+ tenantId
+        			+ ": "
+        			+ " CloudSite does not exist in MSO Configuration";
+        	LOGGER.error (MessageEnum.RA_CONFIG_EXC, error, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Configuration Error");
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.DataError, error);
+        	// Set the detailed error as the Exception 'message'
+        	throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+        }
+
+        // Use MsoNeutronUtils for all NEUTRON commands
+        MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER,msoPropertiesFactory,cloudConfigFactory);
+        MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
+
+        String mode = null;
+        String neutronId = null;
+        // Try Heat first, since networks may be named the same as the Heat stack
+        StackInfo heatStack = null;
+        long queryStackStarttime = System.currentTimeMillis ();
+        try {
+            heatStack = heat.queryStack (cloudSiteId, tenantId, networkNameOrId);
+            LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryStack", null);
+        } catch (MsoException me) {
+        	me.addContext ("QueryNetwork");
+            String error = "Query Network (heat): " + networkNameOrId
+                           + " in "
+                           + cloudSiteId
+                           + "/"
+                           + tenantId
+                           + ": "
+                           + me;
+            LOGGER.recordMetricEvent (queryStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "BPMN", "QueryStack", null);
+            LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "queryStack", MsoLogger.ErrorCode.DataError, "Exception - Query Network (heat)", me);
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+            throw new NetworkException (me);
+        }
+
+        // Populate the outputs based on the returned Stack information
+        if (heatStack != null && heatStack.getStatus () != HeatStatus.NOTFOUND) {
+            // Found it. Get the neutronNetworkId for further query
+            Map <String, Object> outputs = heatStack.getOutputs ();
+            neutronId = (String) outputs.get (NETWORK_ID);
+            mode = "HEAT";
+
+            Map <String, String> sMap = new HashMap <String, String> ();
+            if (outputs != null) {
+            	for (String key : outputs.keySet ()) {
+            		if (key != null && key.startsWith ("subnet_id_")) //multiples subnet_%aaid% outputs
+            		{
+            			String subnetUUId = (String) outputs.get(key); 
+            			sMap.put (key.substring("subnet_id_".length()), subnetUUId);
+            		}
+            		else if (key != null && key.startsWith ("subnet")) //one subnet output expected
+            		{
+            			Map <String, String> map = getSubnetUUId(key, outputs, null); 
+            			sMap.putAll(map);
+            		}
+
+            	}
+            }
+            subnetIdMap.value = sMap;
+        } else {
+            // Input ID was not a Heat stack ID. Try it directly in Neutron
+            neutronId = networkNameOrId;
+            mode = NEUTRON_MODE;
+        }
+
+        // Query directly against the Neutron Network for the details
+        // no RouteTargets available for ContrailV2 in neutron net-show
+        // networkId is heatStackId
+        long queryNetworkStarttime = System.currentTimeMillis ();
+        try {
+            NetworkInfo netInfo = neutron.queryNetwork (neutronId, tenantId, cloudSiteId);
+            LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "QueryNetwork", null);
+            if (netInfo != null) {
+                // Found. Populate the output elements
+                networkExists.value = Boolean.TRUE;
+                if ("HEAT".equals (mode)) {
+                    networkId.value = heatStack.getCanonicalName ();
+                } else {
+                    networkId.value = netInfo.getId ();
+                }
+                neutronNetworkId.value = netInfo.getId ();
+                status.value = netInfo.getStatus ();
+                if (vlans != null)
+                	vlans.value = netInfo.getVlans ();
+
+                LOGGER.debug ("Network " + networkNameOrId
+                              + " found ("
+                              + mode
+                              + "), ID = "
+                              + networkId.value
+                              + ("HEAT".equals (mode) ? ",NeutronId = " + neutronNetworkId.value : ""));
+            } else {
+                // Not found. Populate the status fields, leave the rest null
+                networkExists.value = Boolean.FALSE;
+                status.value = NetworkStatus.NOTFOUND;
+                neutronNetworkId.value = null;
+                if (vlans != null)
+                	vlans.value = new ArrayList <Integer> ();
+
+                LOGGER.debug ("Network " + networkNameOrId + " not found");
+            }
+        } catch (MsoException me) {
+            me.addContext ("QueryNetwork");
+            String error = "Query Network (neutron): " + networkNameOrId
+                           + " in "
+                           + cloudSiteId
+                           + "/"
+                           + tenantId
+                           + ": "
+                           + me;
+            LOGGER.recordMetricEvent (queryNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "QueryNetwork", null);
+            LOGGER.error (MessageEnum.RA_QUERY_NETWORK_EXC, networkNameOrId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.DataError, "Exception - Query Network (neutron)", me);
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+            throw new NetworkException (me);
+        }
+        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully queried network");
+        return;
+    }
+
+    /**
+     * This is the "Delete Network" web service implementation.
+     * It will delete a Network in the specified cloud and tenant.
+     *
+     * If the network is not found, it is treated as a success.
+     *
+     * This service supports two modes of Network creation/update/delete:
+     * - via Heat Templates
+     * - via Neutron API
+     * The network orchestration mode for each network type is declared in its
+     * catalog definition.
+     *
+     * For Heat-based orchestration, the networkId should be the stack ID.
+     * For Neutron-based orchestration, the networkId should be the Neutron network UUID.
+     *
+     * The method returns nothing on success. Rollback is not possible for delete
+     * commands, so any failure on delete will require manual fallout in the client.
+     */
+    @Override
+    public void deleteNetwork (String cloudSiteId,
+                               String tenantId,
+                               String networkType,
+                               String networkId,
+                               MsoRequest msoRequest,
+                               Holder <Boolean> networkDeleted) throws NetworkException {
+        MsoLogger.setLogContext (msoRequest);
+        MsoLogger.setServiceName ("DeleteNetwork");
+        LOGGER.debug ("*** DELETE Network adapter with Network: " + networkId
+                                      + " in "
+                                      + cloudSiteId
+                                      + "/"
+                                      + tenantId);
+
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+
+        try (CatalogDatabase db = getCatalogDb()) {
+            if (isNullOrEmpty (cloudSiteId)
+                            || isNullOrEmpty(tenantId)
+                            || isNullOrEmpty(networkId)) {
+                String error = "Missing mandatory parameter cloudSiteId, tenantId or networkId";
+                LOGGER.error (MessageEnum.RA_MISSING_PARAM, "cloudSiteId or tenantId or networkId", "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing mandatory parameter cloudSiteId, tenantId or networkId");
+                LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+            }
+
+            // Retrieve the Network Resource definition
+            NetworkResource networkResource = db.getNetworkResource (networkType);
+            if (networkResource == null) {
+                String error = "Unknown Network Type: " + networkType;
+                LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Unknown Network Type");
+                LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+            }
+            LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ());
+
+            String mode = networkResource.getOrchestrationMode ();
+
+            if (NEUTRON_MODE.equals (mode)) {
+
+                // Use MsoNeutronUtils for all NEUTRON commands
+                MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
+                long deleteNetworkStarttime = System.currentTimeMillis ();
+                try {
+                    // The deleteNetwork function in MsoNeutronUtils returns success if the network
+                    // was not found. So don't bother to query first.
+                    boolean deleted = neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
+                    LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null);
+                    networkDeleted.value = deleted;
+                } catch (MsoException me) {
+                    me.addContext ("DeleteNetwork");
+                	String error = "Delete Network (neutron): " + networkId
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
+                    LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (neutron)", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+            } else if ("HEAT".equals (mode)) {
+                long deleteStackStarttime = System.currentTimeMillis ();
+                // Use MsoHeatUtils for all HEAT commands
+                MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
+
+                try {
+                    // The deleteStack function in MsoHeatUtils returns NOTFOUND if the stack was not found or if the stack was deleted.
+                    //  So query first to report back if stack WAS deleted or just NOTOFUND 
+                	StackInfo heatStack = null;
+                	heatStack = heat.queryStack(cloudSiteId, tenantId, networkId);
+                	if (heatStack != null && heatStack.getStatus() != HeatStatus.NOTFOUND)
+                	{
+                		heat.deleteStack (tenantId, cloudSiteId, networkId, true);
+                		LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
+                		networkDeleted.value = true;
+                	}
+                	else
+                	{
+                		networkDeleted.value = false;
+                	}
+                } catch (MsoException me) {
+                    me.addContext ("DeleteNetwork");
+                	String error = "Delete Network (heat): " + networkId
+                                   + " in "
+                                   + cloudSiteId
+                                   + "/"
+                                   + tenantId
+                                   + ": "
+                                   + me;
+                    LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
+                    LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "Openstack", "", MsoLogger.ErrorCode.DataError, "Delete Network (heat)", me);
+                    LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                    throw new NetworkException (me);
+                }
+            }
+        }
+
+        // On success, nothing is returned.
+        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully deleted network");
+        return;
+    }
+
+    public CatalogDatabase getCatalogDb() {
+        return new CatalogDatabase();
+    }
+
+    /**
+     * This web service endpoint will rollback a previous Create VNF operation.
+     * A rollback object is returned to the client in a successful creation
+     * response. The client can pass that object as-is back to the rollbackVnf
+     * operation to undo the creation.
+     *
+     * The rollback includes removing the VNF and deleting the tenant if the
+     * tenant did not exist prior to the VNF creation.
+     */
+    @Override
+    public void rollbackNetwork (NetworkRollback rollback) throws NetworkException {
+        MsoLogger.setServiceName ("RollbackNetwork");
+        // Will capture execution time for metrics
+        long startTime = System.currentTimeMillis ();
+
+        if (rollback == null) {
+        	LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "Openstack", "", MsoLogger.ErrorCode.DataError, "rollback is null");
+            LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, "No action to perform");
+            return;
+        }
+
+        MsoLogger.setLogContext (rollback.getMsoRequest());
+
+        // Get the elements of the VnfRollback object for easier access
+        String cloudSiteId = rollback.getCloudId ();
+        String tenantId = rollback.getTenantId ();
+        String networkId = rollback.getNetworkStackId ();
+        String networkType = rollback.getNetworkType ();
+
+        LOGGER.debug ("*** ROLLBACK Network " + networkId + " in " + cloudSiteId + "/" + tenantId);
+
+        // rollback may be null (e.g. if network already existed when Create was called)
+        // Get a handle to the Catalog Database
+
+        try (CatalogDatabase db = getCatalogDb()){
+
+            // Retrieve the Network Resource definition
+            NetworkResource networkResource = db.getNetworkResource (networkType);
+            if (networkResource == null) {
+                String error = "Rollback Network: Unknown Network Type: " + networkType;
+                LOGGER.error (MessageEnum.RA_UNKOWN_PARAM, "Network Type", networkType, "Openstack", "", MsoLogger.ErrorCode.DataError, "Rollback Network: Unknown Network Type");
+                LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.BadRequest, error);
+                throw new NetworkException (error, MsoExceptionCategory.USERDATA);
+            }
+            LOGGER.debug ("Got Network definition from Catalog: " + networkResource.toString ());
+
+            String mode = networkResource.getOrchestrationMode ();
+
+            if (rollback.getNetworkCreated ()) {
+                // Rolling back a newly created network, so delete it.
+                if (NEUTRON_MODE.equals (mode)) {
+                    // Use MsoNeutronUtils for all NEUTRON commands
+                    MsoNeutronUtils neutron = new MsoNeutronUtils (MSO_PROP_NETWORK_ADAPTER, cloudConfigFactory);
+                    long deleteNetworkStarttime = System.currentTimeMillis ();
+                    try {
+                        // The deleteNetwork function in MsoNeutronUtils returns success if the network
+                        // was not found. So don't bother to query first.
+                        neutron.deleteNetwork (networkId, tenantId, cloudSiteId);
+                        LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteNetwork", null);
+                    } catch (MsoException me) {
+                        me.addContext ("RollbackNetwork");
+                        String error = "Rollback Network (neutron): " + networkId
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.recordMetricEvent (deleteNetworkStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteNetwork", null);
+                        LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (neutron)", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                        throw new NetworkException (me);
+                    }
+                } else if ("HEAT".equals (mode)) {
+                    // Use MsoHeatUtils for all HEAT commands
+                    MsoHeatUtils heat = new MsoHeatUtils (MSO_PROP_NETWORK_ADAPTER, msoPropertiesFactory,cloudConfigFactory);
+                    long deleteStackStarttime = System.currentTimeMillis ();
+                    try {
+                        // The deleteStack function in MsoHeatUtils returns success if the stack
+                        // was not found. So don't bother to query first.
+                        heat.deleteStack (tenantId, cloudSiteId, networkId, true);
+                        LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully received response from Open Stack", "OpenStack", "DeleteStack", null);
+                    } catch (MsoException me) {
+                        me.addContext ("RollbackNetwork");
+                        String error = "Rollback Network (heat): " + networkId
+                                       + " in "
+                                       + cloudSiteId
+                                       + "/"
+                                       + tenantId
+                                       + ": "
+                                       + me;
+                        LOGGER.recordMetricEvent (deleteStackStarttime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error, "OpenStack", "DeleteStack", null);
+                        LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, networkId, cloudSiteId, tenantId, "OpenStack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception - Rollback Network (heat)", me);
+                        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.CommunicationError, error);
+                        throw new NetworkException (me);
+                    }
+                }
+            } 
+        }
+        LOGGER.recordAuditEvent (startTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully rolled back network");
+        return;
+    }
+
+    private String validateNetworkParams (NetworkType neutronNetworkType,
+                                          String networkName,
+                                          String physicalNetwork,
+                                          List <Integer> vlans,
+                                          List <String> routeTargets) {
+        String sep = "";
+        StringBuilder missing = new StringBuilder ();
+        if (isNullOrEmpty(networkName)) {
+            missing.append ("networkName");
+            sep = ",";
+        }
+
+        if (neutronNetworkType == NetworkType.PROVIDER || neutronNetworkType == NetworkType.MULTI_PROVIDER) {
+            if (isNullOrEmpty(physicalNetwork)) {
+                missing.append (sep).append ("physicalNetworkName");
+                sep = ",";
+            }
+            if (vlans == null || vlans.isEmpty ()) {
+                missing.append (sep).append (VLANS);
+            }
+        }
+
+        return missing.toString ();
+    }
+
+    private Map <String, Object> populateNetworkParams (NetworkType neutronNetworkType,
+                                                        String networkName,
+                                                        String physicalNetwork,
+                                                        List <Integer> vlans,
+                                                        List <String> routeTargets,
+                                                        String shared,
+                                                        String external,
+                                                        boolean aic3template) {
+        // Build the common set of HEAT template parameters
+        Map <String, Object> stackParams = new HashMap <String, Object> ();
+        stackParams.put ("network_name", networkName);
+
+        if (neutronNetworkType == NetworkType.PROVIDER) {
+            // For Provider type
+            stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
+            stackParams.put ("vlan", vlans.get (0).toString ());
+        } else if (neutronNetworkType == NetworkType.MULTI_PROVIDER) {
+            // For Multi-provider, PO supports a custom resource extension of ProviderNet.
+            // It supports all ProviderNet properties except segmentation_id, and adds a
+            // comma-separated-list of VLANs as a "segments" property.
+            // Note that this does not match the Neutron definition of Multi-Provider network,
+            // which contains a list of 'segments', each having physical_network, network_type,
+            // and segmentation_id.
+            StringBuilder buf = new StringBuilder ();
+            String sep = "";
+            for (Integer vlan : vlans) {
+                buf.append (sep).append (vlan.toString ());
+                sep = ",";
+            }
+            String csl = buf.toString ();
+
+            stackParams.put (PHYSICAL_NETWORK, physicalNetwork);
+            stackParams.put (VLANS, csl);
+        }
+        if (routeTargets != null && !routeTargets.isEmpty()) {
+            StringBuilder buf = new StringBuilder ();
+            String sep = "";
+            for (String rt : routeTargets) {
+            	if (!isNullOrEmpty(rt))
+            	{
+            		if (aic3template)
+            			buf.append (sep).append ("target:" + rt.toString ());
+            		else
+            			buf.append (sep).append (rt.toString ());
+
+            		sep = ",";
+            	}
+            }
+            String csl = buf.toString ();
+
+            stackParams.put ("route_targets", csl);
+        }
+        if (isNullOrEmpty(shared)) {
+            stackParams.put ("shared", "False");
+        } else {
+            stackParams.put ("shared", shared);
+        }
+        if (isNullOrEmpty(external)) {
+            stackParams.put ("external", "False");
+        } else {
+            stackParams.put ("external", external);
+        }
+        return stackParams;
+    }
+    
+
+    
+    /** policyRef_list structure in stackParams
+    [
+     {
+         "network_policy_refs_data_sequence": {
+             "network_policy_refs_data_sequence_major": "1",
+             "network_policy_refs_data_sequence_minor": "0"
+         }
+     },
+     {
+         "network_policy_refs_data_sequence": {
+             "network_policy_refs_data_sequence_major": "2",
+             "network_policy_refs_data_sequence_minor": "0"
+         }
+     }
+ 	]
+    **/
+    private void mergePolicyRefs(List <String> pFqdns, Map <String, Object> stackParams) throws MsoException {
+		//Resource Property
+		List<ContrailPolicyRef> prlist =  new ArrayList <ContrailPolicyRef> ();
+		int index = 1;
+		for (String pf : pFqdns) {
+			if (!isNullOrEmpty(pf))
+			{
+				ContrailPolicyRef pr = new ContrailPolicyRef();
+				pr.populate(String.valueOf(index), "0");
+				index++;
+				LOGGER.debug("Contrail PolicyRefs Data:" + pr.toString());
+				prlist.add(pr);
+			}
+		}
+		
+		JsonNode node = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper(); 
+			node = mapper.convertValue(prlist, JsonNode.class);
+			String jsonString = mapper.writeValueAsString(prlist);
+			LOGGER.debug("Json PolicyRefs Data:" + jsonString);
+		}
+		catch (Exception e)
+		{
+			String error = "Error creating JsonNode for policyRefs Data";
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "Openstack", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception creating JsonNode for policyRefs Data", e);
+			throw new MsoAdapterException (error);
+		}
+		//update parameters
+		if (pFqdns != null && node != null)
+		{
+			StringBuilder buf = new StringBuilder ();
+			String sep = "";
+			for (String pf : pFqdns) {
+				if (!isNullOrEmpty(pf))
+				{
+					buf.append (sep).append (pf.toString ());
+					sep = ",";
+				}
+			}
+			String csl = buf.toString ();
+			stackParams.put ("policy_refs", csl);
+			stackParams.put ("policy_refsdata", node);
+		}
+
+		LOGGER.debug ("StackParams updated with policy refs");
+		return;
+    }
+    
+    private void mergeRouteTableRefs(List <String> rtFqdns, Map <String, Object> stackParams) throws MsoException {
+		
+		//update parameters
+		if (rtFqdns != null)
+		{
+			StringBuilder buf = new StringBuilder ();
+			String sep = "";
+			for (String rtf : rtFqdns) {
+				if (!isNullOrEmpty(rtf))
+				{
+					buf.append (sep).append (rtf.toString ());
+					sep = ",";
+				}
+			}
+			String csl = buf.toString ();
+			stackParams.put ("route_table_refs", csl);
+		}
+
+		LOGGER.debug ("StackParams updated with route_table refs");
+		return;
+    }
+
+    
+    /*** Subnet Output structure from Juniper
+     {
+    "ipam_subnets": [
+        {
+            "subnet": {
+                "ip_prefix": "10.100.1.0",
+                "ip_prefix_len": 28
+            },
+            "addr_from_start": null,
+            "enable_dhcp": false,
+            "default_gateway": "10.100.1.1",
+            "dns_nameservers": [],
+            "dhcp_option_list": null,
+            "subnet_uuid": "10391fbf-6b9c-4160-825d-2d018b7649cf",
+            "allocation_pools": [
+                {
+                    "start": "10.100.1.3",
+                    "end": "10.100.1.5"
+                },
+                {
+                    "start": "10.100.1.6",
+                    "end": "10.100.1.9"
+                }
+            ],
+            "host_routes": null,
+            "dns_server_address": "10.100.1.13",
+            "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b0"
+        },
+        {
+            "subnet": {
+                "ip_prefix": "10.100.2.16",
+                "ip_prefix_len": 28
+            },
+            "addr_from_start": null,
+            "enable_dhcp": true,
+            "default_gateway": "10.100.2.17",
+            "dns_nameservers": [],
+            "dhcp_option_list": null,
+            "subnet_uuid": "c7aac5ea-66fe-443a-85f9-9c38a608c0f6",
+            "allocation_pools": [
+                {
+                    "start": "10.100.2.18",
+                    "end": "10.100.2.20"
+                }
+            ],
+            "host_routes": null,
+            "dns_server_address": "10.100.2.29",
+            "subnet_name": "subnet_MsoNW1_692c9032-e1a2-4d64-828c-7b9a4fcc05b1"
+        }
+    ],
+    "host_routes": null
+	}
+    ***/
+    private String mergeSubnetsAIC3 (String heatTemplate, List <Subnet> subnets, Map <String, Object> stackParams) throws MsoException {
+
+		//Resource Property
+		List<ContrailSubnet> cslist =  new ArrayList <ContrailSubnet> ();
+		for (Subnet subnet : subnets) {
+			ContrailSubnet cs = new ContrailSubnet();
+			LOGGER.debug("Input Subnet:" + subnet.toString());
+			cs.populateWith(subnet);
+			LOGGER.debug("Contrail Subnet:" + cs.toString());
+			cslist.add(cs);
+		}
+
+		JsonNode node = null;
+		try
+		{
+			ObjectMapper mapper = new ObjectMapper();
+			node = mapper.convertValue(cslist, JsonNode.class);
+			String jsonString = mapper.writeValueAsString(cslist);
+			LOGGER.debug("Json Subnet List:" + jsonString);
+		}
+		catch (Exception e)
+		{
+			String error = "Error creating JsonNode from input subnets";
+			LOGGER.error (MessageEnum.RA_MARSHING_ERROR, error, "", "", MsoLogger.ErrorCode.DataError, "Exception creating JsonNode from input subnets", e);
+			throw new MsoAdapterException (error);
+		}
+		//update parameters
+		if (node != null)
+		{
+			stackParams.put ("subnet_list", node);
+		}
+		//Outputs - All subnets are in one ipam_subnets structure
+		String outputTempl = "  subnet:\n" + "    description: Openstack subnet identifier\n"
+				+ "    value: { get_attr: [network, network_ipam_refs, 0, attr]}\n";
+
+		// append outputs in heatTemplate
+		int outputsIdx = heatTemplate.indexOf ("outputs:");
+		heatTemplate = insertStr (heatTemplate, outputTempl, outputsIdx + 8);
+		LOGGER.debug ("Template updated with all AIC3.0 subnets:" + heatTemplate);
+		return heatTemplate;
+    }
+
+
+    private String mergeSubnets (String heatTemplate, List <Subnet> subnets) throws MsoException {
+
+    		String resourceTempl = "  subnet_%subnetId%:\n" + "    type: OS::Neutron::Subnet\n"
+    				+ "    properties:\n"
+    				+ "      name: %name%\n"
+    				+ "      network_id: { get_resource: network }\n"
+    				+ "      cidr: %cidr%\n";
+
+    		/* make these optional
+                               + "      ip_version: %ipversion%\n"
+                               + "      enable_dhcp: %enabledhcp%\n"
+                               + "      gateway_ip: %gatewayip%\n" 
+                               + "      allocation_pools:\n"
+                               + "       - start: %poolstart%\n"
+                               + "         end: %poolend%\n";
+
+    		 */
+    		
+    		String outputTempl = "  subnet_id_%subnetId%:\n" + "    description: Openstack subnet identifier\n"
+    				+ "    value: {get_resource: subnet_%subnetId%}\n";
+
+    		String curR = "";
+    		String curO = "";
+    		StringBuilder resourcesBuf = new StringBuilder ();
+    		StringBuilder outputsBuf = new StringBuilder ();
+    		for (Subnet subnet : subnets) {
+
+    			// build template for each subnet
+    			curR = resourceTempl;
+    			if (subnet.getSubnetId () != null) {
+    				curR = curR.replace ("%subnetId%", subnet.getSubnetId ());
+    			} else {
+    				String error = "Missing Required AAI SubnetId for subnet in HEAT Template";
+    				LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required AAI ID  for subnet in HEAT Template");
+    				throw new MsoAdapterException (error);
+    			}
+    			
+    			if (subnet.getSubnetName () != null) {
+    				curR = curR.replace ("%name%", subnet.getSubnetName ());
+    			} else {
+    				curR = curR.replace ("%name%", subnet.getSubnetId ());
+    			}
+    			
+    			if (subnet.getCidr () != null) {
+    				curR = curR.replace ("%cidr%", subnet.getCidr ());
+    			} else {
+    				String error = "Missing Required cidr for subnet in HEAT Template";
+    				LOGGER.error (MessageEnum.RA_MISSING_PARAM, error, "Openstack", "", MsoLogger.ErrorCode.DataError, "Missing Required cidr for subnet in HEAT Template");
+    				throw new MsoAdapterException (error);
+    			}
+
+    			if (subnet.getIpVersion () != null) {
+    				curR = curR + "      ip_version: " + subnet.getIpVersion () + "\n";
+    			}
+    			if (subnet.getEnableDHCP () != null) {
+    				curR = curR + "      enable_dhcp: " +  Boolean.toString (subnet.getEnableDHCP ()) + "\n";
+    			}
+    			if (subnet.getGatewayIp () != null && !subnet.getGatewayIp ().isEmpty() ) {
+    				curR = curR + "      gateway_ip: " + subnet.getGatewayIp () + "\n";
+    			}  	
+
+    			if (subnet.getAllocationPools() != null) { 
+    				curR = curR + "      allocation_pools:\n";
+    				for (Pool pool : subnet.getAllocationPools()) 
+    				{
+    					if (!isNullOrEmpty(pool.getStart()) && !isNullOrEmpty(pool.getEnd()))
+    					{
+    						curR = curR + "       - start: " + pool.getStart () + "\n";
+    						curR = curR + "         end: " + pool.getEnd () + "\n";
+    					}
+    				}
+    			}
+
+    			resourcesBuf.append (curR);
+
+    			curO = outputTempl;
+    			curO = curO.replace ("%subnetId%", subnet.getSubnetId ());
+
+    			outputsBuf.append (curO);
+
+    		}
+    		// append resources and outputs in heatTemplate
+    		LOGGER.debug ("Tempate initial:" + heatTemplate);
+    		int outputsIdx = heatTemplate.indexOf ("outputs:");
+    		heatTemplate = insertStr (heatTemplate, outputsBuf.toString (), outputsIdx + 8);
+    		int resourcesIdx = heatTemplate.indexOf ("resources:");
+    		heatTemplate = insertStr (heatTemplate, resourcesBuf.toString (), resourcesIdx + 10);
+
+    		LOGGER.debug ("Template updated with all subnets:" + heatTemplate);
+    		return heatTemplate;
+    }
+
+    private Map <String, String> getSubnetUUId(String key,  Map <String, Object> outputs, List <Subnet> subnets) {
+
+    	Map <String, String> sMap = new HashMap <String, String> ();
+
+    	try{
+    		Object obj = outputs.get(key);
+    		ObjectMapper mapper = new ObjectMapper();
+    		String jStr = mapper.writeValueAsString(obj);
+    		LOGGER.debug ("Subnet_Ipam Output JSON String:" + obj.getClass() + " " + jStr);
+
+    		JsonNode rootNode = mapper.readTree(jStr);
+    		for (JsonNode sNode : rootNode.path("ipam_subnets"))
+    		{
+    			LOGGER.debug("Output Subnet Node" + sNode.toString());
+    			String name = sNode.path("subnet_name").getTextValue();
+    			String uuid = sNode.path("subnet_uuid").getTextValue();
+    			String aaiId = name; // default
+    			// try to find aaiId for name in input subnetList
+    			if (subnets != null)
+    			{
+    				for (Subnet subnet : subnets)
+    				{
+    					if ( subnet !=  null && !isNullOrEmpty(subnet.getSubnetName()))
+    					{		
+    						if (subnet.getSubnetName().equals(name))
+    						{
+    							aaiId = subnet.getSubnetId(); 
+    							break;
+    						}
+    					}
+    				}
+    			}
+    			sMap.put(aaiId, uuid); //bpmn needs aaid to uuid map
+    		}
+    	}
+    	catch (Exception e)
+    	{
+    		LOGGER.error (MessageEnum.RA_MARSHING_ERROR, "error getting subnet-uuids", "Openstack", "", MsoLogger.ErrorCode.DataError, "Exception getting subnet-uuids", e);
+    	}
+
+    	LOGGER.debug ("Return sMap" + sMap.toString());
+    	return sMap;
+    }
+
+    private static String insertStr (String template, String snippet, int index) {
+
+        String updatedTemplate = "";
+
+        LOGGER.debug ("Index:" + index + " Snippet:" + snippet);
+
+        String templateBeg = template.substring (0, index);
+        String templateEnd = template.substring (index);
+
+        updatedTemplate = templateBeg + "\n" + snippet + templateEnd;
+
+        LOGGER.debug ("Template updated with a subnet:" + updatedTemplate);
+        return updatedTemplate;
+    }
+
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java
new file mode 100644
index 0000000..c813534
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/NetworkAdapterRest.java
@@ -0,0 +1,595 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.GenericEntity;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.xml.ws.Holder;
+
+import org.apache.http.HttpStatus;
+
+import org.openecomp.mso.adapters.network.exceptions.NetworkException;
+import org.openecomp.mso.adapters.nwrest.ContrailNetwork;
+import org.openecomp.mso.adapters.nwrest.CreateNetworkError;
+import org.openecomp.mso.adapters.nwrest.CreateNetworkRequest;
+import org.openecomp.mso.adapters.nwrest.CreateNetworkResponse;
+import org.openecomp.mso.adapters.nwrest.DeleteNetworkError;
+import org.openecomp.mso.adapters.nwrest.DeleteNetworkRequest;
+import org.openecomp.mso.adapters.nwrest.DeleteNetworkResponse;
+import org.openecomp.mso.adapters.nwrest.ProviderVlanNetwork;
+import org.openecomp.mso.adapters.nwrest.QueryNetworkError;
+import org.openecomp.mso.adapters.nwrest.QueryNetworkResponse;
+import org.openecomp.mso.adapters.nwrest.RollbackNetworkError;
+import org.openecomp.mso.adapters.nwrest.RollbackNetworkRequest;
+import org.openecomp.mso.adapters.nwrest.RollbackNetworkResponse;
+import org.openecomp.mso.adapters.nwrest.UpdateNetworkError;
+import org.openecomp.mso.adapters.nwrest.UpdateNetworkRequest;
+import org.openecomp.mso.adapters.nwrest.UpdateNetworkResponse;
+import org.openecomp.mso.cloud.CloudConfigFactory;
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.logger.MessageEnum;
+import org.openecomp.mso.logger.MsoLogger;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+import org.openecomp.mso.openstack.beans.NetworkStatus;
+import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
+import org.openecomp.mso.properties.MsoPropertiesFactory;
+
+@Path("/v1/networks")
+public class NetworkAdapterRest {
+	private static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.RA);
+	private static final String TESTING_KEYWORD = "___TESTING___";
+	private final CloudConfigFactory cloudConfigFactory = new CloudConfigFactory();
+	private final MsoPropertiesFactory msoPropertiesFactory = new MsoPropertiesFactory();
+	private final MsoNetworkAdapterImpl adapter = new MsoNetworkAdapterImpl(msoPropertiesFactory, cloudConfigFactory);
+
+	@POST
+	@Path("")
+	@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	public Response createNetwork(CreateNetworkRequest req) {
+		LOGGER.debug("createNetwork enter: " + req.toJsonString());
+		CreateNetworkTask task = new CreateNetworkTask(req);
+		if (req.isSynchronous()) {
+			// This is a synchronous request
+			task.run();
+			return Response
+				.status(task.getStatusCode())
+				.entity(task.getGenericEntityResponse())
+				.build();
+		} else {
+			// This is an asynchronous request
+			try {
+				Thread t1 = new Thread(task);
+				t1.start();
+			} catch (Exception e) {
+				// problem handling create, send generic failure as sync resp to caller
+				LOGGER.error (MessageEnum.RA_CREATE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while create network", e);
+				return Response.serverError().build();
+			}
+			// send sync response (ACK) to caller
+			LOGGER.debug ("createNetwork exit");
+			return Response.status(HttpStatus.SC_ACCEPTED).build();
+		}
+	}
+
+	public class CreateNetworkTask implements Runnable {
+		private final CreateNetworkRequest req;
+		private CreateNetworkResponse response = null;
+		private CreateNetworkError eresp = null;
+		private boolean sendxml;
+
+		public CreateNetworkTask(CreateNetworkRequest req) {
+			this.req = req;
+			this.sendxml = true; // can be set with a field or header later
+		}
+		public int getStatusCode() {
+			return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
+		}
+		public Object getGenericEntityResponse() {
+			return (response != null)
+				? new GenericEntity<CreateNetworkResponse>(response) {}
+				: new GenericEntity<CreateNetworkError>(eresp) {};
+		}
+		private String getResponse() {
+			if (response != null) {
+				return sendxml ? response.toXmlString() : response.toJsonString();
+			} else {
+				return sendxml ? eresp.toXmlString() : eresp.toJsonString();
+			}
+		}
+		@Override
+		public void run() {
+			LOGGER.debug ("CreateNetworkTask start");
+			try {
+				// Synchronous Web Service Outputs
+				Holder<String> networkId = new Holder<String>();
+				Holder<String> neutronNetworkId = new Holder<String>();
+				Holder<String> networkFqdn = new Holder<String>();
+				Holder<Map<String, String>> subnetIdMap = new Holder<Map<String, String>>();
+				Holder<NetworkRollback> rollback = new Holder<NetworkRollback>();
+
+				String cloudsite = req.getCloudSiteId();
+				if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) {
+					String tenant = req.getTenantId();
+					if (tenant != null && tenant.equals(TESTING_KEYWORD)) {
+						throw new NetworkException("testing.");
+					}
+					networkId.value = "479D3D8B-6360-47BC-AB75-21CC91981484";
+					neutronNetworkId.value = "55e55884-28fa-11e6-8971-0017f20fe1b8";
+					networkFqdn.value = "086f70b6-28fb-11e6-8260-0017f20fe1b8";
+					subnetIdMap.value = testMap();
+					rollback.value = new NetworkRollback();
+				} else if (req.isContrailRequest()) {
+					ContrailNetwork ctn = req.getContrailNetwork();
+					if (ctn == null) {
+						ctn = new ContrailNetwork();
+						req.setContrailNetwork(ctn);
+					}
+					adapter.createNetworkContrail(
+						req.getCloudSiteId(),
+						req.getTenantId(),
+						req.getNetworkType(),
+						req.getNetworkName(),
+                        req.getContrailNetwork().getRouteTargets(),
+                        req.getContrailNetwork().getShared(),
+                        req.getContrailNetwork().getExternal(),
+                        req.getFailIfExists(),
+                        req.getBackout(),
+                        req.getSubnets(),
+                        req.getContrailNetwork().getPolicyFqdns(),
+                        req.getContrailNetwork().getRouteTableFqdns(),
+              			req.getMsoRequest(),
+       					networkId,
+						neutronNetworkId,
+						networkFqdn,
+						subnetIdMap,
+						rollback);
+				} else {
+					ProviderVlanNetwork pvn = req.getProviderVlanNetwork();
+					if (pvn == null) {
+						pvn = new ProviderVlanNetwork();
+						req.setProviderVlanNetwork(pvn);
+					}
+					adapter.createNetwork(
+						req.getCloudSiteId(),
+						req.getTenantId(),
+						req.getNetworkType(),
+						req.getNetworkName(),
+						req.getProviderVlanNetwork().getPhysicalNetworkName(),
+						req.getProviderVlanNetwork().getVlans(),
+                        req.getFailIfExists(),
+                        req.getBackout(),
+                        req.getSubnets(),
+                        req.getMsoRequest(),
+    					networkId,
+    					neutronNetworkId,
+    					subnetIdMap,
+    					rollback);
+				}
+				response = new CreateNetworkResponse(
+						req.getNetworkId(),
+						neutronNetworkId.value,
+						rollback.value.getNetworkStackId(),
+						networkFqdn.value,
+						rollback.value.getNetworkCreated(),
+						subnetIdMap.value,
+						rollback.value,
+						req.getMessageId());
+			} catch (NetworkException e) {
+				eresp = new CreateNetworkError(
+					e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId());
+			}
+			if (!req.isSynchronous()) {
+				// This is asynch, so POST response back to caller
+				BpelRestClient bpelClient = new BpelRestClient();
+				bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
+			}
+			LOGGER.debug ("CreateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse());
+		}
+	}
+
+	@DELETE
+	@Path("{aaiNetworkId}")
+	@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	public Response deleteNetwork(
+		@PathParam("aaiNetworkId") String aaiNetworkId,
+		DeleteNetworkRequest req)
+	{
+		LOGGER.debug("deleteNetwork enter: " + req.toJsonString());
+		if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) {
+			return Response
+				.status(HttpStatus.SC_BAD_REQUEST)
+				.type(MediaType.TEXT_PLAIN)
+				.entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")")
+				.build();
+		}
+		DeleteNetworkTask task = new DeleteNetworkTask(req);
+		if (req.isSynchronous()) {
+			// This is a synchronous request
+			task.run();
+			return Response
+				.status(task.getStatusCode())
+				.entity(task.getGenericEntityResponse())
+				.build();
+		} else {
+			// This is an asynchronous request
+			try {
+				Thread t1 = new Thread(task);
+				t1.start();
+			} catch (Exception e) {
+				// problem handling create, send generic failure as sync resp to caller
+				LOGGER.error (MessageEnum.RA_DELETE_NETWORK_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception while delete network", e);
+				return Response.serverError().build();
+			}
+			// send sync response (ACK) to caller
+			LOGGER.debug ("deleteNetwork exit");
+			return Response.status(HttpStatus.SC_ACCEPTED).build();
+		}
+	}
+
+	public class DeleteNetworkTask implements Runnable {
+		private final DeleteNetworkRequest req;
+		private DeleteNetworkResponse response = null;
+		private DeleteNetworkError eresp = null;
+		private boolean sendxml;
+
+		public DeleteNetworkTask(DeleteNetworkRequest req) {
+			this.req = req;
+			this.sendxml = true; // can be set with a field or header later
+		}
+		public int getStatusCode() {
+			return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
+		}
+		public Object getGenericEntityResponse() {
+			return (response != null)
+				? new GenericEntity<DeleteNetworkResponse>(response) {}
+				: new GenericEntity<DeleteNetworkError>(eresp) {};
+		}
+		private String getResponse() {
+			if (response != null) {
+				return sendxml ? response.toXmlString() : response.toJsonString();
+			} else {
+				return sendxml ? eresp.toXmlString() : eresp.toJsonString();
+			}
+		}
+		@Override
+		public void run() {
+			LOGGER.debug("DeleteNetworkTask start");
+			try {
+				Holder<Boolean> networkDeleted = new Holder<Boolean>();
+				if (req.getCloudSiteId().equals(TESTING_KEYWORD)) {
+					networkDeleted.value = true;
+				} else {
+					adapter.deleteNetwork(
+						req.getCloudSiteId(),
+						req.getTenantId(),
+						req.getNetworkType(),
+						req.getNetworkStackId(),
+						req.getMsoRequest(),
+						networkDeleted);
+				}
+				response = new DeleteNetworkResponse(req.getNetworkId(), networkDeleted.value, req.getMessageId());
+			} catch (NetworkException e) {
+				eresp = new DeleteNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId());
+			}
+			if (!req.isSynchronous()) {
+				// This is asynch, so POST response back to caller
+				BpelRestClient bpelClient = new BpelRestClient();
+				bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
+			}
+			LOGGER.debug("DeleteNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse());
+		}
+	}
+
+	@GET
+	@Path("{aaiNetworkId}")
+	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	public Response queryNetwork(
+		@QueryParam("cloudSiteId") String cloudSiteId,
+		@QueryParam("tenantId") String tenantId,
+		@QueryParam("networkStackId") String networkStackId,
+		@QueryParam("skipAAI") String skipAAI,
+		@QueryParam("msoRequest.requestId") String requestId,
+		@QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId,
+		@PathParam("aaiNetworkId") String aaiNetworkId)
+	{
+		//This request responds synchronously only
+		LOGGER.debug ("Query network enter:" + aaiNetworkId);
+		MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId);
+
+		try {
+			int respStatus = HttpStatus.SC_OK;
+			QueryNetworkResponse resp = new QueryNetworkResponse(networkStackId, null, networkStackId, null, null);
+			Holder<Boolean> networkExists = new Holder<Boolean>();
+            Holder<String> networkId = new Holder<String>();
+            Holder<String> neutronNetworkId = new Holder<String>();
+            Holder<NetworkStatus> status = new Holder<NetworkStatus>();
+            Holder<List<String>> routeTargets = new Holder<List<String>>();
+            Holder<Map<String, String>> subnetIdMap = new Holder<Map<String, String>>();
+
+			adapter.queryNetworkContrail(cloudSiteId,  tenantId, aaiNetworkId,  msoRequest,
+				networkExists, networkId, neutronNetworkId, status, routeTargets, subnetIdMap);
+
+			if (!networkExists.value) {
+				LOGGER.debug ("network not found");
+				respStatus = HttpStatus.SC_NOT_FOUND;
+			} else {
+				LOGGER.debug ("network found" + networkId.value + ", status=" + status.value);
+				resp.setNetworkExists(networkExists.value);
+				resp.setNetworkId(networkId.value);
+				resp.setNeutronNetworkId(neutronNetworkId.value);
+				resp.setNetworkStatus(status.value);
+				resp.setRouteTargets(routeTargets.value);
+				resp.setSubnetIdMap(subnetIdMap.value);
+			}
+			LOGGER.debug ("Query network exit");
+			return Response
+				.status(respStatus)
+				.entity(new GenericEntity<QueryNetworkResponse>(resp) {})
+				.build();
+		} catch (NetworkException e) {
+			LOGGER.error (MessageEnum.RA_QUERY_VNF_ERR, aaiNetworkId, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception when query VNF", e);
+			QueryNetworkError err = new QueryNetworkError();
+			err.setMessage(e.getMessage());
+			err.setCategory(MsoExceptionCategory.INTERNAL);
+			return Response
+				.status(HttpStatus.SC_INTERNAL_SERVER_ERROR)
+				.entity(new GenericEntity<QueryNetworkError>(err) {})
+				.build();
+		}
+	}
+
+	@DELETE
+	@Path("{aaiNetworkId}/rollback")
+	@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	public Response rollbackNetwork(
+		RollbackNetworkRequest req)
+	{
+		LOGGER.debug("rollbackNetwork enter: " + req.toJsonString());
+		RollbackNetworkTask task = new RollbackNetworkTask(req);
+		if (req.isSynchronous()) {
+			// This is a synchronous request
+			task.run();
+			return Response
+				.status(task.getStatusCode())
+				.entity(task.getGenericEntityResponse())
+				.build();
+		} else {
+			// This is an asynchronous request
+			try {
+				Thread t1 = new Thread(task);
+				t1.start();
+			} catch (Exception e) {
+				// problem handling create, send generic failure as sync resp to caller
+				LOGGER.error (MessageEnum.RA_ROLLBACK_NULL, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in rollbackNetwork", e);
+				return Response.serverError().build();
+			}
+			// send sync response (ACK) to caller
+			LOGGER.debug("rollbackNetwork exit");
+			return Response.status(HttpStatus.SC_ACCEPTED).build();
+		}
+	}
+
+	public class RollbackNetworkTask implements Runnable {
+		private final RollbackNetworkRequest req;
+		private RollbackNetworkResponse response = null;
+		private RollbackNetworkError eresp = null;
+		private boolean sendxml;
+
+		public RollbackNetworkTask(RollbackNetworkRequest req) {
+			this.req = req;
+			this.sendxml = true; // can be set with a field or header later
+		}
+		public int getStatusCode() {
+			return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
+		}
+		public Object getGenericEntityResponse() {
+			return (response != null)
+				? new GenericEntity<RollbackNetworkResponse>(response) {}
+				: new GenericEntity<RollbackNetworkError>(eresp) {};
+		}
+		private String getResponse() {
+			if (response != null) {
+				return sendxml ? response.toXmlString() : response.toJsonString();
+			} else {
+				return sendxml ? eresp.toXmlString() : eresp.toJsonString();
+			}
+		}
+		@Override
+		public void run() {
+			LOGGER.debug("RollbackNetworkTask start");
+			try {
+				NetworkRollback nwr = req.getNetworkRollback();
+				adapter.rollbackNetwork(nwr);
+				response = new RollbackNetworkResponse(true, req.getMessageId());
+			} catch (NetworkException e) {
+				eresp = new RollbackNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId());
+			}
+			if (!req.isSynchronous()) {
+				// This is asynch, so POST response back to caller
+				BpelRestClient bpelClient = new BpelRestClient();
+				bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
+			}
+			LOGGER.debug("RollbackNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse());
+		}
+	}
+
+	@PUT
+	@Path("{aaiNetworkId}")
+	@Consumes({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	@Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
+	public Response updateNetwork(
+		@PathParam("aaiNetworkId") String aaiNetworkId,
+		UpdateNetworkRequest req)
+	{
+		LOGGER.debug("updateNetwork enter: " + req.toJsonString());
+		if (aaiNetworkId == null || !aaiNetworkId.equals(req.getNetworkId())) {
+			return Response
+				.status(HttpStatus.SC_BAD_REQUEST)
+				.type(MediaType.TEXT_PLAIN)
+				.entity("A&AI NetworkId in URL ("+aaiNetworkId+") does not match content ("+req.getNetworkId()+")")
+				.build();
+		}
+		UpdateNetworkTask task = new UpdateNetworkTask(req);
+		if (req.isSynchronous()) {
+			// This is a synchronous request
+			task.run();
+			return Response
+				.status(task.getStatusCode())
+				.entity(task.getGenericEntityResponse())
+				.build();
+		} else {
+			// This is an asynchronous request
+	    	try {
+	    		Thread t1 = new Thread(task);
+	    		t1.start();
+	    	} catch (Exception e) {
+	    		// problem handling create, send generic failure as sync resp to caller
+	    		LOGGER.error (MessageEnum.RA_UPDATE_NETWORK_ERR, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in updateNetwork", e);
+	    		return Response.serverError().build();
+	    	}
+	    	// send sync response (ACK) to caller
+	    	LOGGER.debug ("updateNetwork exit");
+	    	return Response.status(HttpStatus.SC_ACCEPTED).build();
+		}
+	}
+
+	public class UpdateNetworkTask implements Runnable {
+		private final UpdateNetworkRequest req;
+		private UpdateNetworkResponse response = null;
+		private UpdateNetworkError eresp = null;
+		private boolean sendxml;
+
+		public UpdateNetworkTask(UpdateNetworkRequest req) {
+			this.req = req;
+			this.sendxml = true; // can be set with a field or header later
+		}
+		public int getStatusCode() {
+			return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
+		}
+		public Object getGenericEntityResponse() {
+			return (response != null)
+				? new GenericEntity<UpdateNetworkResponse>(response) {}
+				: new GenericEntity<UpdateNetworkError>(eresp) {};
+		}
+		private String getResponse() {
+			if (response != null) {
+				return sendxml ? response.toXmlString() : response.toJsonString();
+			} else {
+				return sendxml ? eresp.toXmlString() : eresp.toJsonString();
+			}
+		}
+		@Override
+		public void run() {
+			LOGGER.debug("UpdateNetworkTask start");
+			try {
+				Holder<Map<String, String>> subnetIdMap = new Holder<Map<String, String>>();
+				Holder<NetworkRollback> rollback = new Holder<NetworkRollback> ();
+
+				if (req.getCloudSiteId().equals(TESTING_KEYWORD)) {
+					subnetIdMap.value = testMap();
+			        NetworkRollback rb = new NetworkRollback ();
+			        rb.setCloudId(req.getCloudSiteId());
+			        rb.setTenantId(req.getTenantId());
+			        rb.setMsoRequest(req.getMsoRequest());
+			        rollback.value = rb;
+				} else if (req.isContrailRequest()) {
+					ContrailNetwork ctn = req.getContrailNetwork();
+					if (ctn == null) {
+						ctn = new ContrailNetwork();
+						req.setContrailNetwork(ctn);
+					}
+					adapter.updateNetworkContrail(
+						req.getCloudSiteId(),
+						req.getTenantId(),
+						req.getNetworkType(),
+						req.getNetworkStackId(),
+						req.getNetworkName(),
+						req.getContrailNetwork().getRouteTargets(),
+	                    req.getContrailNetwork().getShared(),
+	                    req.getContrailNetwork().getExternal(),
+	                    req.getSubnets(),
+	                    req.getContrailNetwork().getPolicyFqdns(),
+	                    req.getContrailNetwork().getRouteTableFqdns(),
+	                    req.getMsoRequest(),
+	                    subnetIdMap,
+	                    rollback);
+				} else {
+					ProviderVlanNetwork pvn = req.getProviderVlanNetwork();
+					if (pvn == null) {
+						pvn = new ProviderVlanNetwork();
+						req.setProviderVlanNetwork(pvn);
+					}
+					adapter.updateNetwork(
+						req.getCloudSiteId(),
+						req.getTenantId(),
+						req.getNetworkType(),
+						req.getNetworkStackId(),
+						req.getNetworkName(),
+						req.getProviderVlanNetwork().getPhysicalNetworkName(),
+						req.getProviderVlanNetwork().getVlans(),
+						req.getSubnets(),
+						req.getMsoRequest(),
+						subnetIdMap,
+						rollback);
+				}
+				response = new UpdateNetworkResponse(
+					req.getNetworkId(),
+					null,	// NeutronNetworkId is not available from an update
+					subnetIdMap.value,
+					req.getMessageId());
+			} catch (NetworkException e) {
+				eresp = new UpdateNetworkError(e.getMessage(), MsoExceptionCategory.INTERNAL, true, req.getMessageId());
+			}
+			if (!req.isSynchronous()) {
+				// This is asynch, so POST response back to caller
+				BpelRestClient bpelClient = new BpelRestClient();
+				bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
+			}
+			LOGGER.debug("UpdateNetworkTask exit: code=" + getStatusCode() + ", resp="+ getResponse());
+		}
+	}
+
+	public static Map<String, String> testMap() {
+		Map<String, String> m = new HashMap<String, String>();
+		m.put("mickey", "7");
+		m.put("clyde", "10");
+		m.put("wayne", "99");
+		return m;
+    }
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java
new file mode 100644
index 0000000..0fd4d02
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkException.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network.exceptions;
+
+
+
+import javax.xml.ws.WebFault;
+
+import org.openecomp.mso.adapters.network.exceptions.NetworkExceptionBean;
+import org.openecomp.mso.openstack.exceptions.MsoException;
+import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
+
+/**
+ * This class simply extends Exception (without addition additional functionality)
+ * to provide an identifier for Network related exceptions on create, delete, query.
+ * 
+ *
+ */
+@WebFault (name="NetworkException", faultBean="org.openecomp.mso.adapters.network.exceptions.NetworkExceptionBean", targetNamespace="http://com.att.mso/network")
+public class NetworkException extends Exception {
+
+	private static final long serialVersionUID = 1L;
+
+	private NetworkExceptionBean faultInfo;
+	
+	public NetworkException (String msg) {
+		super(msg);
+		faultInfo = new NetworkExceptionBean (msg);
+	}
+	
+	public NetworkException (Throwable e) {
+		super(e);
+		faultInfo = new NetworkExceptionBean (e.getMessage());
+	}
+	
+	public NetworkException (String msg, Throwable e) {
+		super (msg, e);
+		faultInfo = new NetworkExceptionBean (msg);
+	}
+
+	public NetworkException (String msg, MsoExceptionCategory category) {
+		super(msg);
+		faultInfo = new NetworkExceptionBean (msg, category);
+	}
+	
+	public NetworkException (String msg, MsoExceptionCategory category, Throwable e) {
+		super (msg, e);
+		faultInfo = new NetworkExceptionBean (msg, category);
+	}
+	
+	public NetworkException (MsoException e) {
+		super (e);
+		faultInfo = new NetworkExceptionBean (e.getContextMessage(), e.getCategory());
+	}
+	
+	public NetworkExceptionBean getFaultInfo() {
+		return faultInfo;
+	}
+
+	public void setFaultInfo(NetworkExceptionBean faultInfo) {
+		this.faultInfo = faultInfo;
+	}
+}
diff --git a/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java
new file mode 100644
index 0000000..af4e0e3
--- /dev/null
+++ b/adapters/mso-network-adapter/src/main/java/org/openecomp/mso/adapters/network/exceptions/NetworkExceptionBean.java
@@ -0,0 +1,73 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network.exceptions;
+
+
+import java.io.Serializable;
+
+import org.openecomp.mso.openstack.exceptions.MsoExceptionCategory;
+
+/**
+ * Jax-WS Fault Bean for Network Exceptions
+ */
+public class NetworkExceptionBean implements Serializable {
+
+    private static final long serialVersionUID = 1655343530371342871L;
+
+    private String message;
+	private MsoExceptionCategory category;
+	private Boolean rolledBack;
+
+	public NetworkExceptionBean () {}
+
+	public NetworkExceptionBean (String message) {
+		this.message = message;
+	}
+
+	public NetworkExceptionBean (String message, MsoExceptionCategory category) {
+		this.message = message;
+		this.category = category;
+	}
+
+	public String getMessage() {
+		return message;
+	}
+
+	public void setMessage(String message) {
+		this.message = message;
+	}
+
+	public MsoExceptionCategory getCategory () {
+		return category;
+	}
+
+	public void setCategory (MsoExceptionCategory category) {
+		this.category = category;
+	}
+
+	public Boolean isRolledBack() {
+		return rolledBack;
+	}
+
+	public void setRolledBack(Boolean rolledBack) {
+		this.rolledBack = rolledBack;
+	}
+}
diff --git a/adapters/mso-network-adapter/src/test/java/org/openecomp/mso/adapters/network/NetworkAdapterTest.java b/adapters/mso-network-adapter/src/test/java/org/openecomp/mso/adapters/network/NetworkAdapterTest.java
new file mode 100644
index 0000000..41cc3f5
--- /dev/null
+++ b/adapters/mso-network-adapter/src/test/java/org/openecomp/mso/adapters/network/NetworkAdapterTest.java
@@ -0,0 +1,266 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * OPENECOMP - MSO
+ * ================================================================================
+ * 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.mso.adapters.network;
+
+
+import static org.junit.Assert.assertTrue;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.ws.Holder;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import org.openecomp.mso.adapters.network.exceptions.NetworkException;
+import org.openecomp.mso.db.catalog.CatalogDatabase;
+import org.openecomp.mso.db.catalog.beans.NetworkResource;
+import org.openecomp.mso.entity.MsoRequest;
+import org.openecomp.mso.openstack.beans.NetworkStatus;
+import org.openecomp.mso.openstack.beans.Subnet;
+import org.openecomp.mso.openstack.beans.NetworkRollback;
+
+public class NetworkAdapterTest {
+
+    @Mock
+    private static MsoNetworkAdapterImpl adapter;
+
+    @Mock
+    private static CatalogDatabase db;
+
+    @BeforeClass
+    public static final void prepare () {
+        adapter = Mockito.spy (new MsoNetworkAdapterImpl ());
+        db = Mockito.mock (CatalogDatabase.class);
+        NetworkResource networkResource = new NetworkResource ();
+        networkResource.setNetworkType ("PROVIDER");
+        networkResource.setNeutronNetworkType ("PROVIDER");
+        networkResource.setId (1);
+        networkResource.setOrchestrationMode ("toto");
+        Mockito.when (db.getNetworkResource ("PROVIDER")).thenReturn (networkResource);
+        Mockito.when (adapter.getCatalogDb()).thenReturn (db);
+    }
+
+    @Test
+    public void createTest () {
+
+        List <Integer> vlans = new LinkedList <> ();
+        vlans.add (1);
+        vlans.add (2);
+        List <Subnet> subnets = new LinkedList <> ();
+        subnets.add (new Subnet ());
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <String> networkId = new Holder <> ();
+        Holder <String> neutronNetworkId = new Holder <> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        Holder <NetworkRollback> rollback = new Holder <> ();
+        try {
+            adapter.createNetwork ("toto",
+                                   "tenant",
+                                   "PROVIDER",
+                                   "networkName",
+                                   "physicalNetworkName",
+                                   vlans,
+                                   Boolean.TRUE,
+                                   Boolean.TRUE,
+                                   subnets,
+                                   msoRequest,
+                                   networkId,
+                                   neutronNetworkId,
+                                   subnetIdMap,
+                                   rollback);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Configuration Error"));
+        }
+    }
+
+    @Test
+    public void createTest2 () {
+        List <Integer> vlans = new LinkedList <> ();
+        vlans.add (1);
+        vlans.add (2);
+        List <Subnet> subnets = new LinkedList <> ();
+        List <String> routeTargets = new LinkedList <> ();
+        subnets.add (new Subnet ());
+        List <String> policyFqdns = new LinkedList <> ();
+        policyFqdns.add("pfqdn1");
+        policyFqdns.add("pfqdn2");
+        List <String> routeTableFqdns = new LinkedList <> ();
+        routeTableFqdns.add("rtfqdn1");
+        routeTableFqdns.add("rtfqdn2");
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <String> networkId = new Holder <> ();
+        Holder <String> neutronNetworkId = new Holder <> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        Holder <NetworkRollback> rollback = new Holder <> ();
+        Holder <String> networkFqdn= new Holder <> ();
+        try {
+            adapter.createNetworkContrail ("toto",
+                                           "tenant",
+                                           "PROVIDER",
+                                           "networkName",
+                                           routeTargets,
+                                           "shared",
+                                           "external",
+                                           Boolean.TRUE,
+                                           Boolean.TRUE,
+                                           subnets,
+                                           policyFqdns,
+                                           routeTableFqdns,
+                                           msoRequest,
+                                           networkId,
+                                           neutronNetworkId,
+                                           networkFqdn,
+                                           subnetIdMap,
+                                           rollback);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Configuration Error"));
+        }
+    }
+
+    @Test
+    public void updateTest () {
+        List <Integer> vlans = new LinkedList <> ();
+        vlans.add (1);
+        vlans.add (2);
+        List <Subnet> subnets = new LinkedList <> ();
+        subnets.add (new Subnet ());
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        Holder <NetworkRollback> rollback = new Holder <> ();
+        try {
+            adapter.updateNetwork ("toto",
+                                   "tenant",
+                                   "PROVIDER",
+                                   "networkId",
+                                   "networkName",
+                                   "physicalNetworkName",
+                                   vlans,
+                                   subnets,
+                                   msoRequest,
+                                   subnetIdMap,
+                                   rollback);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Configuration Error"));
+        }
+    }
+
+    @Test
+    public void updateTest2 () {
+        List <Integer> vlans = new LinkedList <> ();
+        vlans.add (1);
+        vlans.add (2);
+        List <Subnet> subnets = new LinkedList <> ();
+        List <String> routeTargets = new LinkedList <> ();
+        subnets.add (new Subnet ());
+        List <String> policyFqdns = new LinkedList <> ();
+        policyFqdns.add("pfqdn1");
+        List <String> routeTableFqdns = new LinkedList <> ();
+        routeTableFqdns.add("rtfqdn1");
+        routeTableFqdns.add("rtfqdn2");
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        Holder <NetworkRollback> rollback = new Holder <> ();
+        try {
+            adapter.updateNetworkContrail ("toto",
+                                           "tenant",
+                                           "PROVIDER",
+                                           "networkId",
+                                           "networkName",
+                                           routeTargets,
+                                           "shared",
+                                           "external",
+                                           subnets,
+                                           policyFqdns,
+                                           routeTableFqdns,
+                                           msoRequest,
+                                           subnetIdMap,
+                                           rollback);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Configuration Error"));
+        }
+    }
+
+    @Test
+    public void queryTest () {
+        Holder <List <Integer>> vlans = new Holder <> ();
+        Holder <NetworkStatus> status = new Holder <> ();
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <String> networkId = new Holder <> ();
+        Holder <Boolean> result = new Holder <> ();
+        Holder <String> neutronNetworkId = new Holder <> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        try {
+            adapter.queryNetwork (null,
+                                  "tenant",
+                                  "networkName",
+                                  msoRequest,
+                                  result,
+                                  networkId,
+                                  neutronNetworkId,
+                                  status,
+                                  vlans,
+                                  subnetIdMap);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Missing mandatory parameter"));
+        }
+    }
+
+    @Test
+    public void queryTest2 () {
+        Holder <List <String>> routeTargets = new Holder <> ();
+        Holder <NetworkStatus> status = new Holder <> ();
+        MsoRequest msoRequest = new MsoRequest ();
+        Holder <String> networkId = new Holder <> ();
+        Holder <Boolean> result = new Holder <> ();
+        Holder <String> neutronNetworkId = new Holder <> ();
+        Holder <Map <String, String>> subnetIdMap = new Holder <> ();
+        try {
+            adapter.queryNetworkContrail (null,
+                                          "tenant",
+                                          "networkName",
+                                          msoRequest,
+                                          result,
+                                          networkId,
+                                          neutronNetworkId,
+                                          status,
+                                          routeTargets,
+                                          subnetIdMap);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Missing mandatory parameter"));
+        }
+    }
+
+    @Test
+    public void deleteTest () {
+        Holder <Boolean> networkDeleted = new Holder<> ();
+        MsoRequest msoRequest = new MsoRequest ();
+        try {
+            adapter.deleteNetwork ("toto", "tenant", "PROVIDER", "networkId", msoRequest, networkDeleted);
+        } catch (NetworkException e) {
+            assertTrue (e.getMessage ().contains ("Configuration Error"));
+        }
+    }
+}
diff --git a/adapters/mso-network-adapter/src/test/resources/logback-test.xml b/adapters/mso-network-adapter/src/test/resources/logback-test.xml
new file mode 100644
index 0000000..d2c1719
--- /dev/null
+++ b/adapters/mso-network-adapter/src/test/resources/logback-test.xml
@@ -0,0 +1,48 @@
+<!--
+  ============LICENSE_START=======================================================
+  ECOMP MSO
+  ================================================================================
+  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=========================================================
+  -->
+
+<configuration >
+  
+  
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{MM/dd-HH:mm:ss.SSS}|%X{RequestId}|%X{ServiceInstanceId}|%thread|%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}||%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}||%X{Timer}|%msg%n</pattern>
+    </encoder>
+  </appender>
+
+
+  <logger name="com.att.eelf.audit" level="info" additivity="false">
+    <appender-ref ref="STDOUT" />
+  </logger>
+  
+  <logger name="com.att.eelf.metrics" level="info" additivity="false">
+        <appender-ref ref="STDOUT" />
+  </logger>
+
+  <logger name="com.att.eelf.error" level="trace" additivity="false">
+    <appender-ref ref="STDOUT" />
+  </logger> 
+
+  <root level="info">
+    <appender-ref ref="STDOUT" />
+  </root>
+ 
+
+</configuration>