Initial commit for Federated Gateway 79/179/2
authorAshwin Sharma <as214g@att.com>
Thu, 30 Nov 2017 08:55:05 +0000 (02:55 -0600)
committerAshwin Sharma <as214g@att.com>
Thu, 30 Nov 2017 22:45:07 +0000 (16:45 -0600)
Change-Id: I23c4988e022574f3e27c073bb063bcda440ecbe6
Signed-off-by: Ashwin Sharma <as214g@att.com>
90 files changed:
.gitignore [new file with mode: 0644]
.gitreview [new file with mode: 0644]
README.md [new file with mode: 0644]
docs/federated-gateway.rst [new file with mode: 0644]
docs/index.rst [new file with mode: 0644]
docs/release-notes.rst [new file with mode: 0644]
gateway/acumosa.sh [new file with mode: 0644]
gateway/acumosb.sh [new file with mode: 0644]
gateway/application-adapter.properties [new file with mode: 0644]
gateway/application-gateway.properties [new file with mode: 0644]
gateway/application-onap.properties [new file with mode: 0644]
gateway/application.properties [new file with mode: 0644]
gateway/application.properties.template [new file with mode: 0644]
gateway/pom.xml [new file with mode: 0644]
gateway/src/license/acumos/header.txt [new file with mode: 0644]
gateway/src/license/acumos/license.txt [new file with mode: 0644]
gateway/src/license/licenses.properties [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/Application.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/Ghost.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAP.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAPAdapterCondition.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDC.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDCException.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/AdapterCondition.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/FederationClientConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/FederationDataClientConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/GatewayCondition.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/GatewayConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/GhostAdapterCondition.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/HttpClientConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/JSONTags.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/JsonRequest.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/JsonResponse.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/APIConstants.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/APINames.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/EELFLoggerDelegate.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/SwaggerConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/package-info.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/controller/AbstractController.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/controller/FederatedCatalogController.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/controller/PeerCommunicationTaskScheduler.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/controller/package-info.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/event/PeerSubscriptionEvent.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/security/X509AuthenticationFilter.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/FederatedCatalogService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/PeerAcumosConfigService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/PeerAcumosSubscriptionService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/AbstractClient.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/AbstractServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/Clients.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/FederatedCatalogServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/FederatedCatalogServiceLocalImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/FederationClient.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/FederationDataClient.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerAcumosConfigServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerAcumosServiceLocalImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerAcumosSubscriptionServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/package-info.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/package-info.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/task/PeerCommunicationTask.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/task/package-info.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/Action.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/Future.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/FutureHandler.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/Futures.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/JSONHttpMessageConverter.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/ListBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/LocalWatchService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/MapBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/Utils.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/util/package-info.java [new file with mode: 0644]
gateway/src/main/resources/application-gateway.properties [new file with mode: 0644]
gateway/src/main/resources/application.properties [new file with mode: 0644]
gateway/src/main/resources/logback.xml [new file with mode: 0644]
gateway/src/main/resources/peerssubscriptions.json [new file with mode: 0644]
gateway/src/main/resources/server-keystore.jks [new file with mode: 0644]
gateway/src/main/resources/server-public.cer [new file with mode: 0644]
gateway/src/main/resources/server-truststore.jks [new file with mode: 0644]
gateway/src/test/java/org/federated/gateway/AppTest.java [new file with mode: 0644]
gateway/src/test/resources/acumosTrustStore.jks [new file with mode: 0644]
gateway/src/test/resources/acumosa-catalog.json [new file with mode: 0644]
gateway/src/test/resources/acumosa-peers.json [new file with mode: 0644]
gateway/src/test/resources/acumosa.pkcs12 [new file with mode: 0644]
gateway/src/test/resources/acumosb-catalog.json [new file with mode: 0644]
gateway/src/test/resources/acumosb-peers.json [new file with mode: 0644]
gateway/src/test/resources/acumosb.pkcs12 [new file with mode: 0644]
gateway/src/test/resources/application-acumosa.properties [new file with mode: 0644]
gateway/src/test/resources/application-acumosb.properties [new file with mode: 0644]
pom.xml [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3a2a1cf
--- /dev/null
@@ -0,0 +1,6 @@
+.classpath
+.project
+/.settings/
+/bin/
+/logs/
+/target/
diff --git a/.gitreview b/.gitreview
new file mode 100644 (file)
index 0000000..13eb8a8
--- /dev/null
@@ -0,0 +1,4 @@
+[gerrit]
+host=gerrit.acumos.org
+port=29418
+project=federated-cognita.git
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..f4504f7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# Acumos Federation
+
+This repository is to support Federation Architecture for the Acumos Platform. 
+
+Please see the documentation in the "docs" folder.
+
diff --git a/docs/federated-gateway.rst b/docs/federated-gateway.rst
new file mode 100644 (file)
index 0000000..b928840
--- /dev/null
@@ -0,0 +1,30 @@
+Building and Packaging
+----------------------
+
+Prerequisites
+~~~~~~~~~~~~~
+
+The build machine needs the following:
+
+1. Java version 1.8
+2. Maven version 3
+3. Connectivity to Maven Central (for most jars)
+
+Use below maven command to build and package the gateway service into a single jar::
+
+       mvn clean package
+
+Development and Local Testing
+-----------------------------
+
+This section provides information for developing and testing the Fedrated Gateway locally. We will run two instances of the gateway to depict 2 instance of acumos federated to each other.
+In below scenario, we are going to run Acumos A and Acumos B for testing locally.
+
+Launching
+~~~~~~~~~
+
+Start the microservice for development and testing like this::
+
+       java -Djavax.net.ssl.trustStore=src/test/resources/acumosTrustStore.jks -Djavax.net.ssl.trustStorePassword=acumos -jar target/federated-gateway-1.0.0-SNAPSHOT.jar --spring.profiles.active="default,acumosa" 
+
+       java -Djavax.net.ssl.trustStore=src/test/resources/acumosTrustStore.jks -Djavax.net.ssl.trustStorePassword=acumos -jar target/federated-gateway-1.0.0-SNAPSHOT.jar --spring.profiles.active="default,acumosb"
\ No newline at end of file
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644 (file)
index 0000000..46feb76
--- /dev/null
@@ -0,0 +1,8 @@
+Federated Gateway
+-----------
+    
+.. toctree::
+       :maxdepth: 2
+    
+       federated-gateway.rst
+       release-notes.rst
\ No newline at end of file
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
new file mode 100644 (file)
index 0000000..2addd7d
--- /dev/null
@@ -0,0 +1,11 @@
+=============
+Release Notes
+=============
+
+The Federated Gateway is a dockerized spring boot application.  
+
+1.2.0, 2017-11-28
+---------------------------
+* Support to CDS 1.9.0
+* 2-Way SSL Support
+* X509 Subject Principal Authentication
\ No newline at end of file
diff --git a/gateway/acumosa.sh b/gateway/acumosa.sh
new file mode 100644 (file)
index 0000000..2b717fb
--- /dev/null
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+#java -Djavax.net.ssl.trustStore=src/test/resources/acumosTrustStore.jks -Djavax.net.ssl.trustStorePassword=acumos -Djavax.net.debug=all -jar target/federated-gateway-1.0.0-SNAPSHOT.jar --spring.profiles.active="default,acumosa" 
+java -Djavax.net.ssl.trustStore=src/test/resources/acumosTrustStore.jks -Djavax.net.ssl.trustStorePassword=acumos -Djava.security.egd=file:/dev/./urandom -jar target/gateway-1.0.0-SNAPSHOT.jar --spring.profiles.active="default,acumosa" 
diff --git a/gateway/acumosb.sh b/gateway/acumosb.sh
new file mode 100644 (file)
index 0000000..db6e103
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+java -Djavax.net.ssl.trustStore=src/test/resources/acumosTrustStore.jks -Djavax.net.ssl.trustStorePassword=acumos -Djava.security.egd=file:/dev/./urandom  -jar target/gateway-1.0.0-SNAPSHOT.jar --spring.profiles.active="default,acumosb"
diff --git a/gateway/application-adapter.properties b/gateway/application-adapter.properties
new file mode 100644 (file)
index 0000000..2ff5b55
--- /dev/null
@@ -0,0 +1,10 @@
+# REST endpoint configuration; i.e., where this server listens
+server.port=8086
+
+#Instance of this component could be gateway or adapter
+#Based on the value configured, the behavior of this instance will vary.
+federated.instance=adapter
+federated.instance.name=ONAP
+
+#local config
+peersLocal.sourceUri=file:///home/jora/
diff --git a/gateway/application-gateway.properties b/gateway/application-gateway.properties
new file mode 100644 (file)
index 0000000..5a12218
--- /dev/null
@@ -0,0 +1,30 @@
+#Instance of this component could be gateway or adapter
+#Based on the value configured, the behavior of this instance will vary.
+federated.instance=gateway
+federated.instance.name=ATT
+federated.peerGatewayOperator=d468656f-57d0-46e3-9f94-7ffa4f66dc03
+
+security.user.name=federated_client
+#security.user.password = ENC(CTQD7Xk5bOIuC4MaqRZtzjW1K4ArjCjr)
+security.user.password=federated_pass
+management.security.roles=SUPERUSER
+
+# CDmS REST endpoints are protected by HTTP Basic Authentication
+#Common Data Source Configuration
+cdms.client.url=http://localhost:8002/ccds
+#cdms.client.url=http://localhost:8082/ccds
+cdms.client.username=ccds_client
+cdms.client.password=ccds_client
+#cdms.client.password=ccds_pass
+
+#nexus
+#replace nexus_repo_host with actual nexus host name
+nexus.url=http://nexus_repo_host:8081/repository/repo_acumos_model_maven
+nexus.username=acumos_model_rw
+nexus.password=not4you
+nexus.groupId=com.artifact
+nexus.proxy=http://some.proxy.com:8080
+
+nexus.tempFolder=acumos
+
+
diff --git a/gateway/application-onap.properties b/gateway/application-onap.properties
new file mode 100644 (file)
index 0000000..e81ca6d
--- /dev/null
@@ -0,0 +1,3 @@
+#onap
+onap.sdcUri=http://Test:123456@135.21.125.105:8080#demo
+onap.sdcRootPath=/sdc/v1/catalog/
diff --git a/gateway/application.properties b/gateway/application.properties
new file mode 100644 (file)
index 0000000..5144396
--- /dev/null
@@ -0,0 +1,11 @@
+# REST endpoint configuration; i.e., where this server listens
+#server.address=127.0.0.1
+server.port=8084
+server.contextPath=/
+
+#Task executor that run every x seconds
+peer.jobchecker.interval=300
+
+
+
+
diff --git a/gateway/application.properties.template b/gateway/application.properties.template
new file mode 100644 (file)
index 0000000..7b60fdb
--- /dev/null
@@ -0,0 +1,35 @@
+##########################################################################
+########Property Files controlled by External docker-compose file#########
+
+# REST endpoint configuration; i.e., where this server listens
+server.port=8084
+server.contextPath=/
+
+#Instance of this component could be gateway or adapter
+#Based on the value configured, the behavior of this instance will vary.
+federated.instance=gateway
+federated.instance.name=ATT
+
+#Task executor that run every x seconds
+peer.jobchecker.interval=300
+
+security.user.name=federated_client
+#security.user.password = ENC(CTQD7Xk5bOIuC4MaqRZtzjW1K4ArjCjr)
+security.user.password=federated_pass
+management.security.roles=SUPERUSER
+
+
+# CDmS REST endpoints are protected by HTTP Basic Authentication
+#Common Data Source Configuration
+cdms.client.url=http://10.1.0.6:8002/ccds
+cdms.client.username=ccds_client
+cdms.client.password=CTQD7Xk5bOIuC4MaqRZtzjW1K4ArjCjr
+
+#nexus
+#replace nexus_repo_host with actual nexus host name
+nexus.url=http://nexus_repo_host:8081/repository/repo_acumos_model_maven
+nexus.username=acumos_model_rw
+nexus.password=not4you
+nexus.groupId=com.artifact
+nexus.proxy=http://some.proxy.com:8080
+###################################################################
\ No newline at end of file
diff --git a/gateway/pom.xml b/gateway/pom.xml
new file mode 100644 (file)
index 0000000..917aa43
--- /dev/null
@@ -0,0 +1,335 @@
+<?xml version="1.0"?>
+<project
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+       xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+       <modelVersion>4.0.0</modelVersion>
+       <groupId>org.acumos</groupId>
+       <artifactId>gateway</artifactId>
+       <version>1.0.0-SNAPSHOT</version>
+       <name>gateway</name>
+       <description>Federated Acumos Interface for inter-acumos and ONAP communication</description>
+
+       <parent>
+               <groupId>org.springframework.boot</groupId>
+               <artifactId>spring-boot-starter-parent</artifactId>
+               <version>1.5.4.RELEASE</version>
+       </parent>
+       <!--
+       <parent>
+               <groupId>org.springframework.boot</groupId>
+               <artifactId>spring-boot-starter-parent</artifactId>
+               <version>1.5.4.RELEASE</version>
+       </parent>
+       -->
+
+       <properties>
+               <encoding>UTF-8</encoding>
+               <!-- Stand-alone RESTFul application -->
+               <start-class>org.acumos.federation.gateway.Application</start-class>
+               <!-- Jenkins invokes mvn with argument -Dbuild.number=${BUILD_NUMBER} -->
+               <build.number>0</build.number>
+               <eelf.version>1.0.0</eelf.version>
+               <!-- tests require database to be running -->
+               <skipTests>true</skipTests>
+               <!-- Docker daemon -->
+               <docker.host.url>unix:/var/run/docker.sock</docker.host.url>
+               <!-- Docker image registry -->
+               <docker.registry.url>Set by Jenkins</docker.registry.url>
+               <docker.registry.login>Registry userId - supplied by jenkins</docker.registry.login>
+               <docker.registry.password>Registry password - supplied by jenkins</docker.registry.password>
+               <!-- dependencies versions -->
+               <slf4j.version>1.7.25</slf4j.version>
+               <logback.version>1.2.3</logback.version>
+               <spring.boot.devtools.version>1.5.8.RELEASE</spring.boot.devtools.version>
+               <spring.boot.starter.web.version>1.5.8.RELEASE</spring.boot.starter.web.version>
+               <spring.boot.starter.security.version>1.5.8.RELEASE</spring.boot.starter.security.version>
+               <spring.boot.starter.test.version>1.5.8.RELEASE</spring.boot.starter.test.version>
+               <spring.boot.configuration.processor.version>1.5.8.RELEASE</spring.boot.configuration.processor.version>
+               <acumos.nexus.url>Set by Jenkins</acumos.nexus.url>
+               <acumos.nexus.snapshot.path>Set by Jenkins</acumos.nexus.snapshot.path>
+               <acumos.nexus.release.path>Set by Jenkins</acumos.nexus.release.path>
+       </properties>
+
+       <dependencies>
+               <dependency>
+             <groupId>org.json</groupId>
+             <artifactId>json</artifactId>
+             <version>20160212</version>
+           </dependency>
+               <dependency>
+                       <groupId>org.slf4j</groupId>
+                       <artifactId>slf4j-api</artifactId>
+                       <version>${slf4j.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-classic</artifactId>
+                       <version>${logback.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>ch.qos.logback</groupId>
+                       <artifactId>logback-core</artifactId>
+                       <version>${logback.version}</version>
+               </dependency>
+               <!--
+               <dependency>
+                       <groupId>org.acumos</groupId>
+                       <artifactId>acumos-docker-client</artifactId>
+                       <version>1.0.0-SNAPSHOT</version>
+               </dependency>
+               -->
+               <dependency>
+                       <groupId>org.acumos</groupId>
+                       <artifactId>acumos-nexus-client</artifactId>
+                       <version>1.10.9</version>
+               </dependency>
+               <dependency>
+       <groupId>org.springframework.boot</groupId>
+               <artifactId>spring-boot-starter-security</artifactId>
+                       <version>${spring.boot.starter.security.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework.boot</groupId>
+                       <artifactId>spring-boot-starter-web</artifactId>
+                       <version>${spring.boot.starter.web.version}</version>
+               </dependency>
+               
+               <dependency>
+                       <groupId>org.springframework.boot</groupId>
+                       <artifactId>spring-boot-starter-test</artifactId>
+                       <version>${spring.boot.starter.test.version}</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.springframework.boot</groupId>
+                       <artifactId>spring-boot-configuration-processor</artifactId>
+                       <version>${spring.boot.configuration.processor.version}</version>
+                       <optional>true</optional>
+               </dependency>
+               <dependency>
+                   <groupId>org.apache.httpcomponents</groupId>
+                   <artifactId>httpclient</artifactId>
+                   <version>4.5</version>
+               </dependency>
+               <dependency>
+       <groupId>org.springframework.shell</groupId>
+       <artifactId>spring-shell</artifactId>
+       <version>1.2.0.RELEASE</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.acumos.common-dataservice</groupId>
+                       <artifactId>cmn-data-svc-client</artifactId>
+                       <version>1.9.0-SNAPSHOT</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger2</artifactId>
+                       <version>2.6.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.springfox</groupId>
+                       <artifactId>springfox-swagger-ui</artifactId>
+                       <version>2.6.1</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.att.eelf</groupId>
+                       <artifactId>eelf-core</artifactId>
+                       <version>${eelf.version}</version>
+               </dependency>
+               <dependency>
+                       <groupId>javax.inject</groupId>
+                       <artifactId>javax.inject</artifactId>
+                       <version>1</version>
+               </dependency>
+               <dependency>
+                       <groupId>io.jsonwebtoken</groupId>
+                       <artifactId>jjwt</artifactId>
+                       <version>0.6.0</version>
+               </dependency>
+               <dependency>
+               <groupId>org.python</groupId>
+               <artifactId>jython-standalone</artifactId>
+               <version>2.7.1-rc3</version>
+               </dependency>
+               <dependency>
+                       <groupId>junit</groupId>
+                       <artifactId>junit</artifactId>
+                       <version>3.8.1</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+               <groupId>commons-cli</groupId>
+               <artifactId>commons-cli</artifactId>
+               <version>1.2</version>
+               </dependency>
+               <dependency>
+               <groupId>org.apache.commons</groupId>
+               <artifactId>commons-lang3</artifactId>
+               <version>3.6</version>
+               </dependency>
+       </dependencies>
+       
+       <build>
+               <plugins>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-compiler-plugin</artifactId>
+                               <configuration>
+                                       <source>1.8</source>
+                                       <target>1.8</target>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-jar-plugin</artifactId>
+                               <configuration>
+                                       <archive>
+                                               <manifest>
+                                                       <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+                                               </manifest>
+                                               <manifestEntries>
+                                                       <Build-Number>${project.version}.${build.number}</Build-Number>
+                                                       <Build-Time>${maven.build.timestamp}</Build-Time>
+                                               </manifestEntries>
+                                       </archive>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.springframework.boot</groupId>
+                               <artifactId>spring-boot-maven-plugin</artifactId>
+                               <executions>
+                                       <execution>
+                                               <goals>
+                                                       <goal>repackage</goal>
+                                               </goals>
+                                       </execution>
+                               </executions>
+                       </plugin>
+     <!--  <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>2.10</version>
+        <executions>
+          <execution>
+            <id>copy-dependencies</id>
+            <phase>package</phase>
+            <goals>
+              <goal>copy-dependencies</goal>
+            </goals>
+            <configuration>
+              <outputDirectory>${project.build.directory}/deps</outputDirectory>
+              <overWriteReleases>false</overWriteReleases>
+              <overWriteSnapshots>false</overWriteSnapshots>
+              <overWriteIfNewer>true</overWriteIfNewer>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin> -->
+                       <plugin>
+                               <groupId>io.fabric8</groupId>
+                               <artifactId>docker-maven-plugin</artifactId>
+                               <version>0.21.0</version>
+                               <configuration>
+                                       <verbose>true</verbose>
+                                       <dockerHost>${docker.host.url}</dockerHost>
+                                       <registry>${docker.registry.url}</registry>
+                                       <authConfig>
+                                               <username>${docker.registry.login}</username>
+                                               <password>${docker.registry.password}</password>
+                                       </authConfig>
+                                       <images>
+                                               <image>
+                                                       <name>federated-gateway:${project.version}</name>
+                                                       <build>
+                                                               <!-- This is the same FROM used in a Dockerfile -->
+                                                               <from>openjdk:8-jdk</from>
+                                                               <assembly>
+                                                                       <inline>
+                                                                               <files>
+                                                                                       <file>
+                                                                                               <source>application.properties.template</source>
+                                                                                               <outputDirectory />
+                                                                                               <destName>application.properties</destName>
+                                                                                       </file>
+                                                                                       <file>
+                                                                                               <source>acumosa.pkcs12</source>
+                                                                                               <outputDirectory />
+                                                                                               <destName>acumosa.pkcs12</destName>
+                                                                                       </file>
+                                                                                       <file>
+                                                                                               <source>acumosb.pkcs12</source>
+                                                                                               <outputDirectory />
+                                                                                               <destName>acumosb.pkcs12</destName>
+                                                                                       </file>
+                                                                                       <file>
+                                                                                               <source>acumosTrustStore.jks</source>
+                                                                                               <outputDirectory />
+                                                                                               <destName>acumosTrustStore.jks</destName>
+                                                                                       </file>
+                                                                                       <file>
+                                                                                               <source>target/${project.artifactId}-${project.version}.${project.packaging}</source>
+                                                                                               <outputDirectory />
+                                                                                       </file>
+                                                                               </files>
+                                                                       </inline>
+                                                               </assembly>
+                                                               <!-- This is the same CMD used in a Dockerfile -->
+                                                               <cmd>
+                                                                       <shell>cd /maven; java -Djava.security.egd=file:/dev/./urandom -jar ${project.artifactId}-${project.version}.${project.packaging}</shell>
+                                                               </cmd>
+                                                       </build>
+                                               </image>
+                                       </images>
+                               </configuration>
+                       </plugin>
+                       <plugin>
+                       <groupId>org.codehaus.mojo</groupId>
+                       <artifactId>license-maven-plugin</artifactId>
+                       <version>1.14</version>
+                       <configuration>
+                               <licenseName>acumos</licenseName>
+                               <licenseResolver>${project.baseUri}/src/license</licenseResolver>
+                               <addJavaLicenseAfterPackage>false</addJavaLicenseAfterPackage>
+                               <processStartTag>===============LICENSE_START=======================================================</processStartTag>
+                               <processEndTag>===============LICENSE_END=========================================================</processEndTag>
+                               <sectionDelimiter>===================================================================================</sectionDelimiter>
+                               <inceptionYear>2017</inceptionYear>
+                               <organizationName>AT&amp;T Intellectual Property &amp; Tech Mahindra. All rights reserved.</organizationName>
+                               <projectName>Acumos</projectName>
+                               <canUpdateCopyright>true</canUpdateCopyright>
+                               <canUpdateDescription>true</canUpdateDescription>
+                               <canUpdateLicense>true</canUpdateLicense>
+                               <emptyLineAfterHeader>true</emptyLineAfterHeader>
+                               <includes>
+                             <include>**/*.java</include>
+<!--                         <include>**/*.js</include> -->
+<!--                         <include>**/*.ts</include> -->
+                        </includes>
+                       </configuration>
+<!--                   <executions> -->
+<!--                           <execution> -->
+<!--                                   <id>first</id> -->
+<!--                                   <goals> -->
+<!--                                           <goal>update-file-header</goal> -->
+<!--                                   </goals> -->
+<!--                                   <phase>process-sources</phase> -->
+<!--                           </execution> -->
+<!--                   </executions> -->
+                       </plugin>
+               </plugins>
+       </build>
+       <distributionManagement>
+               <snapshotRepository>
+                       <!-- must match ID in Jenkins settings -->
+                       <id>acumos-nexus</id>
+                       <name>acumos-repository-snapshots</name>
+                       <url>${acumos.nexus.url}/${acumos.nexus.snapshot.path}</url>
+               </snapshotRepository>
+               <repository>
+                       <!-- must match ID in Jenkins settings -->
+                       <id>acumos-nexus</id>
+                       <name>acumos-repository-releases</name>
+                       <url>${acumos.nexus.url}/${acumos.nexus.release.path}</url>
+               </repository>
+       </distributionManagement>
+</project>
diff --git a/gateway/src/license/acumos/header.txt b/gateway/src/license/acumos/header.txt
new file mode 100644 (file)
index 0000000..a4d3fc4
--- /dev/null
@@ -0,0 +1,11 @@
+This Acumos software file is distributed by AT&T and Tech Mahindra
+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
+This file 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.
\ No newline at end of file
diff --git a/gateway/src/license/acumos/license.txt b/gateway/src/license/acumos/license.txt
new file mode 100644 (file)
index 0000000..a4d3fc4
--- /dev/null
@@ -0,0 +1,11 @@
+This Acumos software file is distributed by AT&T and Tech Mahindra
+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
+This file 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.
\ No newline at end of file
diff --git a/gateway/src/license/licenses.properties b/gateway/src/license/licenses.properties
new file mode 100644 (file)
index 0000000..36c4443
--- /dev/null
@@ -0,0 +1,21 @@
+###
+# ===============LICENSE_START=======================================================
+# Acumos
+# ===================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+# ===================================================================================
+# This Acumos software file is distributed by AT&T and Tech Mahindra
+# 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
+#  
+# This file 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=========================================================
+###
+
+acumos=acumos
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/Application.java b/gateway/src/main/java/org/acumos/federation/gateway/Application.java
new file mode 100644 (file)
index 0000000..774c24a
--- /dev/null
@@ -0,0 +1,70 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway;
+
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+
+import org.springframework.beans.BeansException;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.scheduling.annotation.EnableScheduling;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+/**
+ * 
+ *
+ */
+@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
+@SpringBootApplication
+public class Application implements ApplicationContextAware {
+
+       private final static EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(Application.class);
+
+       public static final String CONFIG_ENV_VAR_NAME = "SPRING_APPLICATION_JSON";
+
+       public static void main(String[] args) throws Exception {
+               final String springApplicationJson = System.getenv(CONFIG_ENV_VAR_NAME);
+               if (springApplicationJson != null && springApplicationJson.contains("{")) {
+                       final ObjectMapper mapper = new ObjectMapper();
+                       // ensure it's valid
+                       mapper.readTree(springApplicationJson);
+                       logger.info("main: successfully parsed configuration from environment {}", CONFIG_ENV_VAR_NAME);
+               } else {
+                       logger.warn("main: no configuration found in environment {}", CONFIG_ENV_VAR_NAME);
+               }
+               SpringApplication.run(Application.class, args);
+       }
+
+       @Override
+       public void setApplicationContext(ApplicationContext context) throws BeansException {
+               ((ConfigurableEnvironment) context.getEnvironment()).setActiveProfiles("src");
+       }
+
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/Ghost.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/Ghost.java
new file mode 100644 (file)
index 0000000..ba7fec9
--- /dev/null
@@ -0,0 +1,143 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.gateway.adapter;
+
+import java.net.URI;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.client.HttpClientErrorException;
+
+import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.Conditional;
+//import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.common.GhostAdapterCondition;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
+
+import org.acumos.cds.domain.MLPPeer;
+import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+import org.apache.commons.io.IOUtils;
+
+
+@Component("ghost")
+//@Scope("singleton")
+@ConfigurationProperties(prefix="ghost")
+@Conditional(GhostAdapterCondition.class)
+public class Ghost {
+
+       private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(Ghost.class);
+       private TaskExecutor    taskExecutor; 
+
+       private Map<String, Map<String, MLPSolution>>   imports = 
+                                               new HashMap<String, Map<String, MLPSolution>>();
+
+       
+       @PostConstruct
+       public void initGhost() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "initGhost");
+
+               this.taskExecutor = new ThreadPoolTaskExecutor();
+               ((ThreadPoolTaskExecutor)this.taskExecutor).setCorePoolSize(1);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).setMaxPoolSize(1);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).setQueueCapacity(25);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).initialize();
+
+               // Done
+               logger.debug(EELFLoggerDelegate.debugLogger, "Ghost available");
+       }
+
+       @PreDestroy
+       public void cleanupGhost() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "Ghost destroyed");
+       }
+
+       @EventListener
+       public void handlePeerSubscriptionUpdate(PeerSubscriptionEvent theEvent) {
+               logger.info(EELFLoggerDelegate.debugLogger, "received peer subscription update event " + theEvent);
+               taskExecutor.execute(new GhostTask(theEvent.getPeer(), theEvent.getSolutions()));
+       }
+
+
+       public class GhostTask implements Runnable {
+
+               private MLPPeer         peer;
+               private List<MLPSolution> solutions;
+
+               public GhostTask(MLPPeer thePeer, List<MLPSolution> theSolutions) {
+                       this.peer = thePeer;
+                       this.solutions = theSolutions;
+               }
+
+               public void run() {
+
+                       Map<String, MLPSolution> peerImports = null;
+
+                       synchronized (imports) {
+                               peerImports = imports.computeIfAbsent(peer.getPeerId(),
+                                                                                                                                                                                       pid -> new HashMap());
+                       }
+
+                       synchronized (peerImports) {
+                               for (MLPSolution solution: this.solutions) {
+                                       
+                                       MLPSolution peerImport = peerImports.get(solution.getSolutionId());
+                                       if (peerImport == null) {
+                                               logger.debug(EELFLoggerDelegate.debugLogger, "New solution");
+                                               peerImports.put(solution.getSolutionId(), solution);
+                                       }
+                                       else {
+                                               logger.debug(EELFLoggerDelegate.debugLogger, "Existing solution");
+                                               if (peerImport.getModified().equals(solution.getModified())) {
+                                                       logger.debug(EELFLoggerDelegate.debugLogger, "No updates");
+                                               }
+                                               else {
+                                                       logger.debug(EELFLoggerDelegate.debugLogger, "Has updates");
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java
new file mode 100644 (file)
index 0000000..cde94a7
--- /dev/null
@@ -0,0 +1,323 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.adapter;
+
+import java.util.List;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.acumos.federation.gateway.common.GatewayCondition;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
+import org.acumos.federation.gateway.service.impl.Clients;
+import org.acumos.federation.gateway.service.impl.FederationClient;
+import org.acumos.federation.gateway.util.Utils;
+import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.env.Environment;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import org.acumos.cds.AccessTypeCode;
+import org.acumos.cds.ValidationStatusCode;
+import org.acumos.cds.client.CommonDataServiceRestClientImpl;
+import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPPeer;
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+
+
+@Component("peergateway")
+//@Scope("singleton")
+@ConfigurationProperties(prefix="federated")
+@Conditional(GatewayCondition.class)
+public class PeerGateway {
+
+       private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(PeerGateway.class);
+       private String  peerGatewayOperator = "testUser";
+       private TaskExecutor    taskExecutor; 
+       @Autowired
+       private Environment env;
+       @Autowired
+       private Clients clients;
+
+
+       @PostConstruct
+       public void initPeerGateway() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "initPeerGateway");
+
+               /*if (this.asdc.getUri() == null)
+                       throw new BeanInitializationException("Forgot to configure the SDC uri??");*/
+
+               this.taskExecutor = new ThreadPoolTaskExecutor();
+               ((ThreadPoolTaskExecutor)this.taskExecutor).setCorePoolSize(1);
+               ((ThreadPoolTaskExecutor)this.taskExecutor).setMaxPoolSize(1);
+               ((ThreadPoolTaskExecutor)this.taskExecutor).setQueueCapacity(25);
+               ((ThreadPoolTaskExecutor)this.taskExecutor).initialize();
+
+               // Done
+               logger.debug(EELFLoggerDelegate.debugLogger, "PeerGateway available");
+       }
+
+       @PreDestroy
+       public void cleanupOnap() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "PeerGateway destroyed");
+       }
+
+       @EventListener
+       public void handlePeerSubscriptionUpdate(PeerSubscriptionEvent theEvent) {
+               logger.info(EELFLoggerDelegate.debugLogger, "received peer subscription update event " + theEvent);
+               taskExecutor.execute(new PeerGatewayUpdateTask(theEvent.getPeer(), theEvent.getSolutions()));
+       }
+
+
+       public class PeerGatewayUpdateTask implements Runnable {
+
+               private MLPPeer                                         peer;
+               private List<MLPSolution> solutions;
+
+               public PeerGatewayUpdateTask(MLPPeer thePeer, List<MLPSolution> theSolutions) {
+                       this.peer = thePeer;
+                       this.solutions = theSolutions;
+               }
+
+               public void run() {
+
+                       //list with category and subcategory currently used for onap
+                       //more dynamic mapping to come: based on solution information it will provide sdc assettype, categoty and subcategoty
+                       ICommonDataServiceRestClient cdsClient =
+                               new CommonDataServiceRestClientImpl(
+                                                       env.getProperty("cdms.client.url"),
+                                                       env.getProperty("cdms.client.username"),
+                                                       env.getProperty("cdms.client.password"));
+                       
+                       logger.info(EELFLoggerDelegate.debugLogger, "Received Acumos solutions: " + this.solutions);
+
+                       for (MLPSolution acumosSolution: this.solutions) {
+                               try {
+                                       //Check if the Model already exists in the Local Acumos
+                                       MLPSolution mlpSolution  = null;
+                                       try {
+                                               mlpSolution = cdsClient.getSolution(acumosSolution.getSolutionId());
+                                       } catch (Exception e) {
+                                               logger.info(EELFLoggerDelegate.debugLogger, "Solution Id : " + acumosSolution.getSolutionId() + " does not exists locally, Adding it to local catalog ");
+                                       }
+                                       
+                                       //Verify if MLPSolution is not same
+                                       if(mlpSolution != null && !isSameMLPSolution(acumosSolution, mlpSolution)) {
+                                               //if already exists locally then loop through next
+                                               mlpSolution = updateMLPSolution(acumosSolution, mlpSolution, cdsClient);
+                                               
+                                       } else {
+                                               mlpSolution = createMLPSolution(acumosSolution, cdsClient);
+                                       }
+                                       updateMLPSolutionArtifacts(mlpSolution, cdsClient);
+                                       //ONAP.this.asdc.checkinResource(UUID.fromString(sdcAsset.getString("artifactUUID")), ONAP.this.asdcOperator, "solution imported " + " the acumos revision number ");
+                               }
+                               catch (Exception x) {
+                                       logger.warn(EELFLoggerDelegate.debugLogger, "Mapping of acumos solution failed for: " + acumosSolution + ": " + x);
+                               }
+                       }
+               }
+               
+               private MLPSolution createMLPSolution(MLPSolution peerMLPSolution, ICommonDataServiceRestClient cdsClient) {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Creating Local MLP Solutino for peer solution " + peerMLPSolution);
+                       MLPSolution mlpSolution = new MLPSolution();
+                       mlpSolution.setSolutionId(peerMLPSolution.getSolutionId());
+                       mlpSolution.setName(peerMLPSolution.getName());
+                       mlpSolution.setDescription(peerMLPSolution.getDescription());
+                       mlpSolution.setAccessTypeCode(AccessTypeCode.PB.toString());
+                       mlpSolution.setMetadata(peerMLPSolution.getMetadata());
+                       mlpSolution.setModelTypeCode(peerMLPSolution.getModelTypeCode());
+                       mlpSolution.setProvider("ATTAcumosInc");
+                       mlpSolution.setActive(peerMLPSolution.isActive());
+                       mlpSolution.setToolkitTypeCode(peerMLPSolution.getToolkitTypeCode());
+                       mlpSolution.setValidationStatusCode(ValidationStatusCode.PS.toString());
+                       mlpSolution.setCreated(peerMLPSolution.getCreated());
+                       mlpSolution.setModified(peerMLPSolution.getModified());
+                       mlpSolution.setOwnerId(env.getProperty("federated.peerGatewayOperator")); // Need to get from c_user table . It has to be admin user
+                       try {
+                               cdsClient.createSolution(mlpSolution);
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.debugLogger, "createMLPSolution  failed for: ",  e);
+                       }
+                       return mlpSolution;
+               }
+               
+               private MLPSolutionRevision createMLPSolutionRevision(MLPSolutionRevision mlpSolutionRevision, ICommonDataServiceRestClient cdsClient) {
+                       MLPSolutionRevision solutionRevision = new MLPSolutionRevision();
+                       solutionRevision.setSolutionId(mlpSolutionRevision.getSolutionId());
+                       solutionRevision.setRevisionId(mlpSolutionRevision.getRevisionId());
+                       solutionRevision.setVersion(mlpSolutionRevision.getVersion());
+                       solutionRevision.setDescription(mlpSolutionRevision.getDescription());
+                       solutionRevision.setOwnerId(env.getProperty("federated.peerGatewayOperator"));//TODO
+                       solutionRevision.setMetadata(mlpSolutionRevision.getMetadata());
+                       solutionRevision.setCreated(mlpSolutionRevision.getCreated());
+                       solutionRevision.setModified(mlpSolutionRevision.getModified());
+                       try {
+                               cdsClient.createSolutionRevision(solutionRevision);
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.debugLogger, "createMLPSolutionRevision  failed for: ",  e);
+                       }
+                       return solutionRevision;
+               }
+               
+               private MLPArtifact createMLPArtifact(MLPArtifact mlpArtifact, ICommonDataServiceRestClient cdsClient) {
+                       MLPArtifact artifact = new MLPArtifact();
+                       artifact.setArtifactId(mlpArtifact.getArtifactId());
+                       artifact.setArtifactTypeCode(mlpArtifact.getArtifactTypeCode());
+                       artifact.setCreated(mlpArtifact.getCreated());
+                       artifact.setDescription(mlpArtifact.getDescription());
+                       artifact.setMetadata(mlpArtifact.getMetadata());
+                       artifact.setModified(mlpArtifact.getModified());
+                       artifact.setName(mlpArtifact.getName());
+                       artifact.setOwnerId(env.getProperty("federated.peerGatewayOperator"));
+                       artifact.setSize(mlpArtifact.getSize());;
+                       artifact.setUri(mlpArtifact.getUri());
+                       artifact.setVersion(mlpArtifact.getVersion());
+                       try {
+                               cdsClient.createArtifact(artifact);
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.debugLogger, "createMLPArtifact  failed for: ",  e);
+                       }
+                       return artifact;
+               }
+               
+               private MLPArtifact updateMLPArtifact(MLPArtifact peerMLPArtifact, MLPArtifact localMLPArtifact, ICommonDataServiceRestClient cdsClient) {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Updating Local MLP Artifact for peer artifact " + peerMLPArtifact);
+                       
+                       localMLPArtifact.setArtifactId(peerMLPArtifact.getArtifactId());
+                       localMLPArtifact.setArtifactTypeCode(peerMLPArtifact.getArtifactTypeCode());
+                       localMLPArtifact.setCreated(peerMLPArtifact.getCreated());
+                       localMLPArtifact.setDescription(peerMLPArtifact.getDescription());
+                       localMLPArtifact.setMetadata(peerMLPArtifact.getMetadata());
+                       localMLPArtifact.setModified(peerMLPArtifact.getModified());
+                       localMLPArtifact.setName(peerMLPArtifact.getName());
+                       localMLPArtifact.setOwnerId(env.getProperty("federated.peerGatewayOperator"));
+                       localMLPArtifact.setSize(peerMLPArtifact.getSize());;
+                       localMLPArtifact.setUri(peerMLPArtifact.getUri());
+                       localMLPArtifact.setVersion(peerMLPArtifact.getVersion());
+                       try {
+                               cdsClient.updateArtifact(localMLPArtifact);
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.debugLogger, "updateMLPArtifact  failed for: ",  e);
+                       }
+                       return localMLPArtifact;
+               }
+               
+               private MLPSolution updateMLPSolution(MLPSolution peerMLPSolution, MLPSolution localMLPSolution, ICommonDataServiceRestClient cdsClient) {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Updating Local MLP Solutino for peer solution " + peerMLPSolution);
+                       localMLPSolution.setSolutionId(peerMLPSolution.getSolutionId());
+                       localMLPSolution.setName(peerMLPSolution.getName());
+                       localMLPSolution.setDescription(peerMLPSolution.getDescription());
+                       localMLPSolution.setAccessTypeCode(peerMLPSolution.getAccessTypeCode());
+                       localMLPSolution.setMetadata(peerMLPSolution.getMetadata());
+                       localMLPSolution.setModelTypeCode(peerMLPSolution.getModelTypeCode());
+                       localMLPSolution.setProvider(peerMLPSolution.getProvider());
+                       localMLPSolution.setActive(peerMLPSolution.isActive());
+                       localMLPSolution.setToolkitTypeCode(peerMLPSolution.getToolkitTypeCode());
+                       localMLPSolution.setValidationStatusCode(localMLPSolution.getValidationStatusCode());
+                       localMLPSolution.setOwnerId(env.getProperty("federated.peerGatewayOperator")); // Need to get from c_user table . It has to be admin user
+                       try {
+                               cdsClient.updateSolution(localMLPSolution);
+                       } catch (Exception e) {
+                               logger.error(EELFLoggerDelegate.debugLogger, "createMLPSolution  failed for: ",  e);
+                       }
+                       return localMLPSolution;
+               }
+               
+               private boolean isSameMLPSolution(MLPSolution peerMLPSolution, MLPSolution localMLPSolution) {
+                       boolean isSame = false;
+                       if(peerMLPSolution != null && localMLPSolution != null) {
+                               
+                               if((!Utils.isEmptyOrNullString(peerMLPSolution.getName()) && !Utils.isEmptyOrNullString(localMLPSolution.getName()) && localMLPSolution.getName().equalsIgnoreCase(peerMLPSolution.getName()))
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getDescription()) && !Utils.isEmptyOrNullString(localMLPSolution.getDescription()) && localMLPSolution.getDescription().equalsIgnoreCase(peerMLPSolution.getDescription()))
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getAccessTypeCode()) && !Utils.isEmptyOrNullString(localMLPSolution.getAccessTypeCode()) && localMLPSolution.getAccessTypeCode().equalsIgnoreCase(peerMLPSolution.getAccessTypeCode()))
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getMetadata()) && !Utils.isEmptyOrNullString(localMLPSolution.getMetadata()) && localMLPSolution.getMetadata().equalsIgnoreCase(peerMLPSolution.getMetadata()))
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getModelTypeCode()) && !Utils.isEmptyOrNullString(localMLPSolution.getModelTypeCode()) && localMLPSolution.getModelTypeCode().equalsIgnoreCase(peerMLPSolution.getModelTypeCode())) 
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getProvider()) && !Utils.isEmptyOrNullString(localMLPSolution.getProvider()) && localMLPSolution.getProvider().equalsIgnoreCase(peerMLPSolution.getProvider())) 
+                                       || (!Utils.isEmptyOrNullString(peerMLPSolution.getToolkitTypeCode()) && !Utils.isEmptyOrNullString(localMLPSolution.getToolkitTypeCode()) && localMLPSolution.getToolkitTypeCode().equalsIgnoreCase(peerMLPSolution.getToolkitTypeCode()))
+                                       || (Utils.isEmptyOrNullString(peerMLPSolution.getMetadata()) && Utils.isEmptyOrNullString(localMLPSolution.getMetadata()))
+                                       || (Utils.isEmptyOrNullString(peerMLPSolution.getDescription()) && Utils.isEmptyOrNullString(localMLPSolution.getDescription()))
+                                       || (Utils.isEmptyOrNullString(peerMLPSolution.getAccessTypeCode()) && Utils.isEmptyOrNullString(localMLPSolution.getAccessTypeCode()))
+                                       || (Utils.isEmptyOrNullString(peerMLPSolution.getModelTypeCode()) && Utils.isEmptyOrNullString(localMLPSolution.getModelTypeCode()))
+                                       || (Utils.isEmptyOrNullString(peerMLPSolution.getToolkitTypeCode()) && Utils.isEmptyOrNullString(localMLPSolution.getToolkitTypeCode()))) {
+                                       isSame = true;
+                               }
+                       }
+                       return isSame;
+               }
+               
+               public void updateMLPSolutionArtifacts(MLPSolution theSolution,  ICommonDataServiceRestClient cdsClient) throws Exception {
+                       //fetch the solution artifacts: for now we'll do this for the latest acumos revision
+                       FederationClient fedClient =
+                                       clients.getFederationClient(this.peer.getApiUrl());
+
+                       //Get List of all SolutionRevisions for a solution Id
+                       List<MLPSolutionRevision> acumosRevisions = null;
+                       try {
+                               acumosRevisions = (List<MLPSolutionRevision>)
+                                               fedClient.getSolutionsRevisionListFromPeer(theSolution.getSolutionId(), null).getResponseBody();
+                       }
+                       catch (Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to retrieve acumos revisions: " + x);
+                               throw x;
+                       }
+                       
+                       List<MLPArtifact> acumosArtifacts = null;
+                       try {
+                               acumosArtifacts = (List<MLPArtifact>)
+                                               fedClient.getArtifactsListFromPeer(theSolution.getSolutionId(), acumosRevisions.get(acumosRevisions.size()-1).getRevisionId(), null)
+                                               .getResponseBody();
+                       }
+                       catch (Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to retrieve acumos artifacts" + x);
+                               throw x;
+                       }
+                       
+                       MLPSolutionRevision mlpSolutionRevision = cdsClient.getSolutionRevision(theSolution.getSolutionId(), acumosRevisions.get(acumosRevisions.size()-1).getRevisionId());
+                       if(mlpSolutionRevision == null && !Utils.isEmptyList(acumosArtifacts)) {
+                               //If SolutinoRevision is null, we need to create a Solution Revision in Local Acumos
+                               mlpSolutionRevision = createMLPSolutionRevision(acumosRevisions.get(acumosRevisions.size()-1), cdsClient);
+                       } 
+                       
+                       if(mlpSolutionRevision != null) {
+                               for(MLPArtifact artifact : acumosArtifacts) {
+                                       MLPArtifact mlpArtifact = cdsClient.getArtifact(artifact.getArtifactId());
+                                       if(mlpArtifact == null) {
+                                               createMLPArtifact(mlpArtifact, cdsClient);
+                                       } else {
+                                               updateMLPArtifact(artifact, mlpArtifact, cdsClient);
+                                       }
+                               }
+                               
+                       }
+                       
+                       //TODO Artifacts file download and push it to nexus
+               }
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAP.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAP.java
new file mode 100644 (file)
index 0000000..2c93269
--- /dev/null
@@ -0,0 +1,450 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.adapter.onap;
+
+import java.net.URI;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.client.HttpClientErrorException;
+
+import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Scope;
+import org.springframework.context.annotation.Conditional;
+import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.beans.factory.BeanInitializationException;
+import org.springframework.context.event.EventListener;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import org.acumos.federation.gateway.adapter.onap.ONAPAdapterCondition;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
+import org.acumos.federation.gateway.service.impl.Clients;
+import org.acumos.federation.gateway.service.impl.FederationClient;
+
+import org.acumos.cds.domain.MLPPeer;
+import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDC;
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDCException;
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.AssetType;
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.ArtifactType;
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.ArtifactGroupType;
+import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.LifecycleState;
+import org.acumos.federation.gateway.util.MapBuilder;
+
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+import org.apache.commons.io.IOUtils;
+
+
+@Component("onap")
+//@Scope("singleton")
+@ConfigurationProperties(prefix="onap")
+@Conditional(ONAPAdapterCondition.class)
+public class ONAP {
+
+       private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(ONAP.class);
+       private ASDC            asdc = new ASDC();
+       private String  asdcOperator = "admin";
+       private TaskExecutor    taskExecutor; 
+  @Autowired
+  private Clients clients;
+
+       
+       public void setSdcUri(URI theUri) {
+               this.asdc.setUri(theUri);
+       }
+
+       public void setSdcRootPath(String thePath) {
+               this.asdc.setRootPath(thePath);
+       }
+       
+       public void setSdcOperator(String theUid) {
+               this.asdcOperator = theUid;
+       }
+
+       @PostConstruct
+       public void initOnap() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "initOnap");
+
+               if (this.asdc.getUri() == null)
+                       throw new BeanInitializationException("Forgot to configure the SDC uri??");
+
+               this.taskExecutor = new ThreadPoolTaskExecutor();
+               ((ThreadPoolTaskExecutor)this.taskExecutor).setCorePoolSize(1);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).setMaxPoolSize(1);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).setQueueCapacity(25);
+    ((ThreadPoolTaskExecutor)this.taskExecutor).initialize();
+
+               //temporary
+               cleanup();
+
+               // Done
+               logger.debug(EELFLoggerDelegate.debugLogger, "Onap available");
+       }
+
+       @PreDestroy
+       public void cleanupOnap() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "Onap destroyed");
+       }
+
+       @EventListener
+       public void handlePeerSubscriptionUpdate(PeerSubscriptionEvent theEvent) {
+               logger.info(EELFLoggerDelegate.debugLogger, "received peer subscription update event " + theEvent);
+               taskExecutor.execute(new ONAPPushTask(theEvent.getPeer(), theEvent.getSolutions()));
+       }
+
+
+       public class ONAPPushTask implements Runnable {
+
+               private MLPPeer                                         peer;
+               private List<MLPSolution> solutions;
+
+               public ONAPPushTask(MLPPeer thePeer, List<MLPSolution> theSolutions) {
+                       this.peer = thePeer;
+                       this.solutions = theSolutions;
+               }
+
+               public void run() {
+
+                       //list with category and subcategory currently used for onap
+                       //more dynamic mapping to come: based on solution information it will provide sdc assettype, categoty and subcategoty
+               
+                       JSONArray sdcAssets = null;
+                       try {
+                               sdcAssets = asdc.getAssets(AssetType.resource, JSONArray.class, "Generic", "Abstract")
+                                                                                                       .waitForResult();
+                       }
+                       catch (Throwable x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to list ONAP SDC assets: " + x.getCause(), x);
+                               //if this is a 404 NotFound, continue, otherwise, fail
+                               if (x instanceof ASDCException &&
+                                               x.getCause() instanceof HttpClientErrorException &&
+                                               ((HttpClientErrorException)x.getCause()).getStatusCode() == HttpStatus.NOT_FOUND) {
+                                       sdcAssets = new JSONArray();
+                               }
+                               else
+                                       return;
+                       }
+                       //logger.info(EELFLoggerDelegate.debugLogger, "Retrieved ONAP SDC assets: " + sdcAssets);
+                       //logger.info(EELFLoggerDelegate.debugLogger, "Received Acumos solutions: " + this.solutions);
+
+                       for (MLPSolution acumosSolution: this.solutions) {
+                               try {
+                                       //does it already exist in sdc
+                                       JSONObject sdcAsset = lookupSdcAsset(acumosSolution, sdcAssets);
+                                       if (sdcAsset == null) {
+                                               //new solution
+                                               sdcAsset = createSdcAsset(acumosSolution);
+                                       }
+                                       else {
+                                               //ONAP.this.asdc.checkoutResource(UUID.fromString(sdcAsset.getString("artifactUUID")), ONAP.this.asdcOperator, "updated solution import");
+                                               sdcAsset = updateSdcAsset(sdcAsset, acumosSolution);
+                                       }
+                                       updateAssetArtifacts(sdcAsset, acumosSolution);
+                                       //ONAP.this.asdc.checkinResource(UUID.fromString(sdcAsset.getString("artifactUUID")), ONAP.this.asdcOperator, "solution imported " + " the acumos revision number ");
+                               }
+                               catch (Exception x) {
+                                       logger.warn(EELFLoggerDelegate.debugLogger, "Mapping of acumos solution failed for: " + acumosSolution + ": " + x);
+                               }
+                       }
+               }
+
+               public JSONObject lookupSdcAsset(MLPSolution theSolution, JSONArray theAssets) {
+                       if (theAssets == null || theAssets.length() == 0)
+                               return null;
+                       for (int i = 0; i < theAssets.length(); i++) {
+                               JSONObject asset = theAssets.optJSONObject(i);
+                               if (same(theSolution, asset))                           
+                                       return asset;
+                       }
+                       return null;
+               }
+
+               public JSONObject createSdcAsset(MLPSolution theSolution) throws Exception {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Creating ONAP SDC VF for solution " + theSolution);
+
+                       String description = null;//theSolution.getDescription();
+                       if (description == null)
+                               description = theSolution.getSolutionId();// + "@acumos";
+
+                       try {
+                               return
+                                       ONAP.this.asdc.createVF()
+                                                       .withCategory("Generic")
+                                                       .withSubCategory("Abstract")
+                                                       .withName(theSolution.getName() + "-" + theSolution.getSolutionId())  //sdc names are unique, acumos ones not so
+                                                       .withDescription(description)
+                                                       .withVendorName("AcumosInc")
+                                                       .withVendorRelease("1.0") //cannot update so .. but might want to fetch the last Acumos revision version
+                                                       .withTags("acumos", theSolution.getSolutionId()) //can I fit an UUID as tag ??
+                                                       .withOperator(ONAP.this.asdcOperator/*theSolution.getOwnerId()*/) //probably won't work, SDC expects an att uuid
+                                                       .execute()
+                                                       .waitForResult();
+                       }
+                       catch(Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to create ONAP SDC VF", x);
+                               throw x;
+                       }
+               }
+               
+               /**
+                * There is no such thing as updating an asset in the ASDC REST API, we can only update the artifacts ..
+                */
+               public JSONObject updateSdcAsset(JSONObject theAssetInfo, MLPSolution theSolution) throws Exception {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Updating ONAP SDC VF " + theAssetInfo.optString("uuid") + " for Acumosb solution " + theSolution);
+                       return theAssetInfo;
+               }
+
+               public void updateAssetArtifacts(JSONObject theAssetInfo, MLPSolution theSolution) throws Exception {
+                       //fetch the solution artifacts: for now we'll do this for the latest acumos revision
+      FederationClient fedClient =
+          clients.getFederationClient(this.peer.getApiUrl());
+
+                       List<MLPSolutionRevision> acumosRevisions = null;
+                       try {
+                               acumosRevisions = (List<MLPSolutionRevision>)
+                                       fedClient.getSolutionsRevisionListFromPeer(theSolution.getSolutionId(), null).getResponseBody();
+                       }
+                       catch (Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to retrieve acumos revisions: " + x);
+                               throw x;
+                       }
+
+                       List<MLPArtifact> acumosArtifacts = null;
+                       try {
+                               acumosArtifacts = (List<MLPArtifact>)
+                                       fedClient.getArtifactsListFromPeer(theSolution.getSolutionId(), acumosRevisions.get(acumosRevisions.size()-1).getRevisionId(), null)
+                                                                               .getResponseBody();
+                       }
+                       catch (Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to retrieve acumos artifacts" + x);
+                               throw x;
+                       }
+
+                       try {
+                               theAssetInfo = ONAP.this.asdc.getAsset(AssetType.resource, UUID.fromString(theAssetInfo.getString("uuid")), JSONObject.class)
+                                                                                               .waitForResult();
+                       }
+                       catch (Exception x) {
+                               logger.warn(EELFLoggerDelegate.debugLogger, "Failed to retrieve ONAP SDC asset metadata for " + theAssetInfo.getString("uuid") + " : " + x);
+                               throw x;
+                       }
+
+                       JSONArray sdcArtifacts = theAssetInfo.optJSONArray("artifacts");        
+                       if (sdcArtifacts == null)
+                               sdcArtifacts = new JSONArray();
+
+                       //all this could be better writen but the 2 sets are expected to be small so we favor readability
+
+                       //acumos artifacts that do not exist locally need to be added
+                       List<MLPArtifact>                                               newArtifacts = new LinkedList<MLPArtifact>();
+                       Map<MLPArtifact, JSONObject>    updatedArtifacts = new HashMap<MLPArtifact, JSONObject>();
+                       List<JSONObject>                                                        oldArtifacts = new LinkedList<JSONObject>();
+
+                       logger.info(EELFLoggerDelegate.debugLogger, "Acumos artifacts: " + acumosArtifacts);
+                       logger.info(EELFLoggerDelegate.debugLogger, "ONAP SDC artifacts: " + sdcArtifacts);
+               
+                       for (MLPArtifact acumosArtifact: acumosArtifacts) {
+                               boolean found = false;
+                               for (int i = 0; !found && i < sdcArtifacts.length(); i++) {
+                                       JSONObject sdcArtifact = sdcArtifacts.getJSONObject(i);
+                                       String sdcArtifactDescription = sdcArtifact.optString("artifactDescription");
+                                       if (sdcArtifactDescription != null) {   
+                                               String[] parts = sdcArtifactDescription.split("@");
+                                               if (parts.length == 2) {
+                                                       if (parts[0].equals(acumosArtifact.getArtifactId())) {
+                                                               found = true;
+                                                               //compare the versions so that we find the 
+                                                               if (!parts[1].equals(acumosArtifact.getVersion()))
+                                                                       updatedArtifacts.put(acumosArtifact, sdcArtifact);
+                                                       }
+                                               }       
+                                       }
+                               }
+                               if (!found)
+                                       newArtifacts.add(acumosArtifact);
+                       }
+
+                       logger.warn(EELFLoggerDelegate.debugLogger, "New SDC artifacts: " + newArtifacts);
+                       for (MLPArtifact acumosArtifact: newArtifacts) {
+                               try {
+                                       byte[] content = IOUtils.toByteArray(new URI(acumosArtifact.getUri()));
+                                       if (content == null)
+                                               throw new Exception("Unable to fetch artifact content from " + acumosArtifact.getUri());
+                                       if (content.length == 0)
+                                               logger.warn(EELFLoggerDelegate.debugLogger, "Acumos artifact has empty content, not acceptable in ONAP SDC");
+                                       //more sophisticated mapping needed here
+                                       asdc.createAssetArtifact(AssetType.resource, UUID.fromString(theAssetInfo.getString("uuid")))
+                                                       .withOperator(ONAP.this.asdcOperator)
+                                                       .withContent(content)
+                                                       .withLabel(acumosArtifact.getArtifactTypeCode())
+                                                       .withName(acumosArtifact.getName())
+                                                       .withDisplayName(acumosArtifact.getMetadata())
+                                                       .withType(ArtifactType.OTHER)
+                                                       .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                                       .withDescription(acumosArtifact.getArtifactId() + "@" + acumosArtifact.getVersion()/*acumosArtifact.getDescription()*/)
+                                                       .execute()
+                                                       .waitForResult();
+                               }
+                               catch(Exception x) {
+                                       logger.warn(EELFLoggerDelegate.debugLogger, "Failed to create ONAP SDC VF Artifact", x);
+                               }
+                       }
+                       
+                       logger.warn(EELFLoggerDelegate.debugLogger, "Updated SDC artifacts: " + updatedArtifacts.keySet());
+                       for (Map.Entry<MLPArtifact,JSONObject> updateEntry: updatedArtifacts.entrySet()) {
+                               MLPArtifact acumosArtifact = updateEntry.getKey();
+                               try {
+                                       byte[] content = IOUtils.toByteArray(new URI(acumosArtifact.getUri()));
+                                       if (content == null)
+                                               throw new Exception("Unable to fetch artifact content from " + acumosArtifact.getUri());
+                                       //more sophisticated mapping needed here
+                                       asdc.updateAssetArtifact(
+                                                                       AssetType.resource, UUID.fromString(theAssetInfo.getString("uuid")), updateEntry.getValue())
+                                                       .withOperator(ONAP.this.asdcOperator)
+                                                       .withContent(content)
+                                                       //.withName(acumosArtifact.getName())
+                                                       .withDescription(acumosArtifact.getArtifactId() + "@" + acumosArtifact.getVersion()/*acumosArtifact.getDescription()*/)
+                                                       .execute()
+                                                       .waitForResult();
+                               }
+                               catch(Exception x) {
+                                       logger.warn(EELFLoggerDelegate.debugLogger, "Failed to update ONAP SDC VF Artifact", x);
+                               }
+                       }
+                       
+                       //sdc artifacts that do not have a acumos counterpart should be deleted (if they are labeled as having
+                       //originated in acumos).
+                       List<JSONObject> deletedArtifacts = new LinkedList<JSONObject>();
+                       for (int i = 0; i < sdcArtifacts.length(); i++) {
+                               JSONObject sdcArtifact = sdcArtifacts.getJSONObject(i);
+                               boolean found = false;
+                               for (MLPArtifact acumosArtifact: acumosArtifacts) {
+                                       if (same(acumosArtifact, sdcArtifact)) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               if (!found && isAcumosOriginated(sdcArtifact)) {
+                                       deletedArtifacts.add(sdcArtifact);
+                               }
+                       }
+                       logger.warn(EELFLoggerDelegate.debugLogger, "Deleted SDC artifacts: " + deletedArtifacts);
+                       for (JSONObject sdcArtifact: deletedArtifacts) {
+                               try {
+                                       asdc.deleteAssetArtifact(
+                                                                       AssetType.resource,
+                                                                       UUID.fromString(theAssetInfo.getString("uuid")),
+                                                                       UUID.fromString(sdcArtifact.getString("artifactUUID")))
+                                                       .withOperator(ONAP.this.asdcOperator)
+                                                       .execute()
+                                                       .waitForResult();
+                               }
+                               catch(Exception x) {
+                                       logger.warn(EELFLoggerDelegate.debugLogger, "Failed to delete ONAP SDC VF Artifact", x);
+                               }
+                       }
+               }
+               
+               private boolean same(MLPSolution theAcumosSolution, JSONObject theSDCAsset) {
+
+                       return theSDCAsset.optString("name", "").equals(
+                                                               theAcumosSolution.getName() + "-" + theAcumosSolution.getSolutionId());
+               }
+
+               private boolean same(MLPArtifact theAcumosArtifact, JSONObject theSDCArtifact) {
+                                       
+                       String sdcArtifactDescription = theSDCArtifact.optString("artifactDescription");
+                       if (sdcArtifactDescription != null) {   
+                               String[] parts = sdcArtifactDescription.split("@");
+                               if (parts.length == 2) {
+                                       if (parts[0].equals(theAcumosArtifact.getArtifactId())) {
+                                               return true;
+                                       }
+                               }
+                       }
+                       return false;
+               }
+
+               //only safe to call if 'same' returned true
+               private boolean sameVersion(MLPArtifact theAcumosArtifact, JSONObject theSDCArtifact) {
+                       return theSDCArtifact.optString("artifactDescription","@").split("@")[1].equals(theAcumosArtifact.getVersion());
+               }
+
+               private boolean isAcumosOriginated(JSONObject theSDCArtifact) {
+                       boolean isAcumos = theSDCArtifact.optString("artifactType").equals(ArtifactType.OTHER.toString()) &&
+                                                                                                       theSDCArtifact.optString("artifactGroupType").equals(ArtifactGroupType.DEPLOYMENT.toString());
+                       String[] parts = theSDCArtifact.optString("artifactDescription","@").split("@");
+                       isAcumos &= (parts.length == 2); //and the first part can be parsed as an UUID
+                       return isAcumos;
+               }
+       }
+
+       /**
+        * Removes all (non-commited) Acumos solutions imported into ONAP SDC
+        */
+       protected void cleanup() {
+               
+               JSONArray sdcAssets = null;
+               try {
+                       sdcAssets = asdc.getAssets(AssetType.resource, JSONArray.class, "Generic", "Abstract")
+                                                                                               .waitForResult();
+               }
+               catch (Throwable x) {
+                       logger.info(EELFLoggerDelegate.debugLogger, "Cleanup failed to list ONAP SDC assets: " + x.getCause(), x);
+               }
+
+               if (sdcAssets == null)
+                       return;
+
+               for (int i = 0; i < sdcAssets.length(); i++) {
+                       JSONObject sdcAsset = sdcAssets.optJSONObject(i);
+                       String state = sdcAsset.optString("lifecycleState");
+                       if (state != null && "NOT_CERTIFIED_CHECKEOUT".equals(state)) {
+                               try {
+                                       asdc.cycleAsset(AssetType.resource, UUID.fromString(sdcAsset.getString("uuid")), LifecycleState.undocheckout, ONAP.this.asdcOperator, null)
+                                                       .waitForResult();
+                               }
+                               catch (Exception x) {
+                                       logger.info(EELFLoggerDelegate.debugLogger, "Cleanup ONAP SDC asset: " + sdcAsset.optString("uuid"), x);
+                               }
+                       }
+               }
+
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAPAdapterCondition.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAPAdapterCondition.java
new file mode 100644 (file)
index 0000000..314025b
--- /dev/null
@@ -0,0 +1,43 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.adapter.onap;
+
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.env.Environment;
+
+import org.acumos.federation.gateway.common.AdapterCondition;
+
+/**
+ */
+public class ONAPAdapterCondition extends AdapterCondition {
+
+       @Override
+       public boolean matches(ConditionContext theContext, 
+                                                                                                AnnotatedTypeMetadata theMetadata) {
+
+               Environment env = theContext.getEnvironment();
+    return super.matches(theContext, theMetadata) &&
+                                        null != env &&
+                                        "ONAP".equals(env.getProperty("federated.instance.name"));
+  }
+
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDC.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDC.java
new file mode 100644 (file)
index 0000000..8a2dddd
--- /dev/null
@@ -0,0 +1,1533 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.adapter.onap.sdc;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.net.ssl.HttpsURLConnection;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+
+import java.util.List;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.UUID;
+import java.util.Collections;
+
+import java.util.function.BiFunction;
+import java.util.function.UnaryOperator;
+
+import java.util.logging.Logger;
+import java.util.logging.Level;
+
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipEntry;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+
+import org.springframework.http.MediaType;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpRequest;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.RequestEntity;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.client.AsyncClientHttpRequestExecution;
+import org.springframework.http.client.AsyncClientHttpRequestInterceptor;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.client.AsyncRestTemplate;
+import org.springframework.web.client.RestClientException;
+import org.springframework.web.client.HttpClientErrorException;
+import org.springframework.web.client.DefaultResponseErrorHandler;
+import org.springframework.http.converter.HttpMessageConverter;
+
+import org.springframework.util.Base64Utils;
+//import org.springframework.util.DigestUtils;
+import org.apache.commons.codec.digest.DigestUtils;
+
+import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Scope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+import org.springframework.util.concurrent.ListenableFuture;
+import org.springframework.util.concurrent.ListenableFutureCallback;
+
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.acumos.federation.gateway.util.JSONHttpMessageConverter;
+import org.acumos.federation.gateway.util.Action;
+import org.acumos.federation.gateway.util.Future;
+import org.acumos.federation.gateway.util.Futures;
+
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+import org.apache.commons.cli.BasicParser;
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.OptionBuilder;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+
+
+@Component("asdc")
+@Scope("singleton")
+@ConfigurationProperties(prefix="asdc")
+public class ASDC {
+       
+       public static enum AssetType {
+               resource,
+               service,
+               product
+       }
+
+       public static enum ArtifactType {
+               DCAE_TOSCA,
+               DCAE_JSON,
+               DCAE_POLICY,
+               DCAE_DOC,
+               DCAE_EVENT,
+               DCAE_INVENTORY_TOSCA,
+               DCAE_INVENTORY_JSON,
+               DCAE_INVENTORY_POLICY,
+               DCAE_INVENTORY_DOC,
+               DCAE_INVENTORY_BLUEPRINT,
+               DCAE_INVENTORY_EVENT,
+               HEAT,
+               HEAT_VOL,
+               HEAT_NET,
+               HEAT_NESTED,
+               HEAT_ARTIFACT,
+               HEAT_ENV,
+               OTHER
+       }
+
+       public static enum ArtifactGroupType {
+               DEPLOYMENT,
+               INFORMATIONAL
+       }
+
+       public static enum LifecycleState {
+               Checkin,
+               Checkout,
+               Certify,
+               undocheckout
+       }
+
+       
+//     @Retention(RetentionPolicy.RUNTIME)
+//     @Target(ElementType.METHOD)
+//     public @interface Mandatory {
+//     }
+
+       private Logger log = Logger.getLogger(ASDC.class.getName());
+
+       private URI                     rootUri;
+       private String  rootPath = "/asdc/"; //"/sdc1/feproxy/"; //"/sdc/v1/catalog/";
+       private String  user,
+                                                                       passwd;
+       private String  instanceId;
+
+       public void setUri(URI theUri) {
+               String userInfo = theUri.getUserInfo();
+               if (userInfo != null) {
+                       String[] userInfoParts = userInfo.split(":");
+                       setUser(userInfoParts[0]);
+                       if (userInfoParts.length > 1)
+                               setPassword(userInfoParts[1]);
+               }
+               String fragment = theUri.getFragment();
+               if (fragment == null)
+                       throw new IllegalArgumentException("The URI must contain a fragment specification, to be used as ASDC instance id");
+               setInstanceId(fragment);
+
+               try {
+                       this.rootUri = new URI(theUri.getScheme(), null, theUri.getHost(), theUri.getPort(), theUri.getPath(), theUri.getQuery(), null);
+               }
+               catch (URISyntaxException urix) {
+                       throw new IllegalArgumentException("Invalid uri", urix);
+               }
+       }
+
+       public URI getUri() {
+               return this.rootUri;    
+       }
+
+       public void setUser(String theUser) {
+               this.user = theUser;
+       }
+
+       public String getUser() {
+               return this.user;
+       }
+
+       public void setPassword(String thePassword) {
+               this.passwd = thePassword;
+       }
+
+       public String getPassword() {
+               return this.passwd;
+       }
+
+       public void setInstanceId(String theId) {
+               this.instanceId = theId;
+       }
+
+       public String getInstanceId() {
+               return this.instanceId;
+       }
+       
+       public void setRootPath(String thePath) {
+               this.rootPath = thePath;
+       }
+
+       public String getRootPath() {
+               return this.rootPath;
+       }
+
+  @Scheduled(fixedRateString = "${beans.context.scripts.updateCheckFrequency?:60000}")
+       public void checkForUpdates() { 
+       }
+
+       @PostConstruct
+       public void initASDC() {
+       }
+
+       public <T> Future<T> getResources(Class<T> theType) {
+               return getAssets(AssetType.resource, theType);
+       }
+       
+       public Future<JSONArray> getResources() {
+               return getAssets(AssetType.resource, JSONArray.class);
+       }
+       
+       public <T> Future<T> getResources(Class<T> theType, String theCategory, String theSubCategory) {
+               return getAssets(AssetType.resource, theType, theCategory, theSubCategory);
+       }
+       
+       public Future<JSONArray> getResources(String theCategory, String theSubCategory) {
+               return getAssets(AssetType.resource, JSONArray.class, theCategory, theSubCategory);
+       }
+
+       public <T> Future<T> getServices(Class<T> theType) {
+               return getAssets(AssetType.service, theType);
+       }
+       
+       public Future<JSONArray> getServices() {
+               return getAssets(AssetType.service, JSONArray.class);
+       }
+       
+       public <T> Future<T> getServices(Class<T> theType, String theCategory, String theSubCategory) {
+               return getAssets(AssetType.service, theType, theCategory, theSubCategory);
+       }
+       
+       public Future<JSONArray> getServices(String theCategory, String theSubCategory) {
+               return getAssets(AssetType.service, JSONArray.class, theCategory, theSubCategory);
+       }
+
+       public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType) {
+               return fetch(refAssets(theAssetType), theType);
+       }
+       
+       public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType) {
+               return (() -> fetch(refAssets(theAssetType), theType));
+       }
+       
+       public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType,
+                                                                                                                                String theCategory, String theSubCategory) {
+               return getAssets(theAssetType, theType, theCategory, theSubCategory, null);
+       }
+
+       public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType,
+                                                                                                                                String theCategory, String theSubCategory, String theResourceType) {
+               return fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType);
+       }
+       
+       public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType,
+                                                                                                                                                        String theCategory, String theSubCategory, String theResourceType) {
+               return (() -> fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType));
+       }
+       
+       protected String refAssets(AssetType theAssetType) {
+               return this.rootPath + theAssetType + "s/";
+       }
+
+       private String filter(String theCategory, String theSubCategory, String theResourceType) {
+               StringBuilder filter = null;
+               if (theCategory != null) {
+                       filter = new StringBuilder();
+                       filter.append("?category=")
+                                               .append(theCategory);
+                       if (theSubCategory != null) {
+                               filter.append("&subCategory=")
+                                                       .append(theSubCategory);
+                               if (theResourceType != null) {
+                                       filter.append("&resourceType=")
+                                                               .append(theResourceType);
+                               }
+                       }
+               }
+               return filter == null ? "" : filter.toString();
+       }
+
+       protected String refAsset(AssetType theAssetType, UUID theId) {
+               return this.rootPath + theAssetType + "s/" + theId;
+       }
+       
+       public <T> Future<T> getResource(UUID theId, Class<T> theType) {
+               return getAsset(AssetType.resource, theId, theType);
+       }
+       
+       public Future<JSONObject> getResource(UUID theId) {
+               return getAsset(AssetType.resource, theId, JSONObject.class);
+       }
+
+       public <T> Future<T> getService(UUID theId, Class<T> theType) {
+               return getAsset(AssetType.service, theId, theType);
+       }
+       
+       public Future<JSONObject> getService(UUID theId) {
+               return getAsset(AssetType.service, theId, JSONObject.class);
+       }
+
+       public <T> Future<T> getAsset(AssetType theAssetType, UUID theId, Class<T> theType) {
+               return fetch(refAsset(theAssetType, theId) + "/metadata", theType);
+       }
+       
+       public <T> Action<T> getAssetAction(AssetType theAssetType, UUID theId, Class<T> theType) {
+               return (() -> fetch(refAsset(theAssetType, theId) + "/metadata", theType));
+       }
+
+       public Future<byte[]> getResourceArchive(UUID theId) {
+               return getAssetArchive(AssetType.resource, theId);
+       }
+
+       public Future<byte[]> getServiceArchive(UUID theId) {
+               return getAssetArchive(AssetType.service, theId);
+       }
+
+       public Future<byte[]> getAssetArchive(AssetType theAssetType, UUID theId) {
+               return fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class);
+       }
+
+       public Action<byte[]> getAssetArchiveAction(AssetType theAssetType, UUID theId) {
+               return (() -> fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class));
+       }
+
+       public Future<JSONObject> checkinResource(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.resource, theId, LifecycleState.Checkin, theUser, theMessage);
+       }
+
+       public Future<JSONObject> checkinService(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.service, theId, LifecycleState.Checkin, theUser, theMessage);
+       }
+
+       public Future<JSONObject> checkoutResource(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.resource, theId, LifecycleState.Checkout, theUser, theMessage);
+       }
+
+       public Future<JSONObject> checkoutService(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.service, theId, LifecycleState.Checkout, theUser, theMessage);
+       }
+       
+       public Future<JSONObject> certifyResource(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.resource, theId, LifecycleState.Certify, theUser, theMessage);
+       }
+
+       public Future<JSONObject> certifyService(UUID theId, String theUser, String theMessage) {
+               return cycleAsset(AssetType.service, theId, LifecycleState.Certify, theUser, theMessage);
+       }
+
+       /* Normally theMessage is mandatory (and we'd use put instead of putOpt) but .. not so for undocheckout ..
+        */
+       public Future<JSONObject> cycleAsset(AssetType theAssetType, UUID theId, LifecycleState theState,
+                                                                                                                                                        String theUser, String theMessage) {
+               return post(refAsset(theAssetType, theId)       + "/lifecycleState/" + theState,
+                                                         (headers) -> prepareHeaders(headers)
+                                                                                                                       .header("USER_ID", theUser),
+                                                               new JSONObject().putOpt("userRemarks", theMessage));
+       }
+
+       protected String refAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theAssetInstance, UUID theArtifactId) {
+               return refAsset(theAssetType, theAssetId) + "/resourceInstances/" + theAssetInstance + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId));
+       }
+
+       protected String refAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) {
+               return refAsset(theAssetType, theAssetId) + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId));
+       }
+       
+       public <T> Future<T> getResourceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) {
+               return getAssetArtifact(AssetType.resource, theAssetId, theArtifactId, theType);
+       }
+       
+       public <T> Future<T> getServiceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) {
+               return getAssetArtifact(AssetType.service, theAssetId, theArtifactId, theType);
+       }
+       
+       public <T> Future<T> getResourceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) {
+               return getAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId, theType);
+       }
+       
+       public <T> Future<T> getServiceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) {
+               return getAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId, theType);
+       }
+
+       public <T> Future<T> getAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) {
+               return fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType);
+       }
+       
+       public <T> Action<T> getAssetArtifactAction(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) {
+               return (() -> fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType));
+       }
+       
+       public <T> Future<T> getAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) {
+               return fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType);
+       }
+       
+       public <T> Action<T> getAssetInstanceArtifactAction(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) {
+               return (() -> fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType));
+       }
+       
+       public ArtifactUploadAction createResourceArtifact(UUID theAssetId) {
+               return createAssetArtifact(AssetType.resource, theAssetId);
+       }
+       
+       public ArtifactUploadAction createServiceArtifact(UUID theAssetId) {
+               return createAssetArtifact(AssetType.service, theAssetId);
+       }
+       
+       public ArtifactUploadAction createResourceInstanceArtifact(UUID theAssetId, String theInstance) {
+               return createAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance);
+       }
+       
+       public ArtifactUploadAction createServiceInstanceArtifact(UUID theAssetId, String theInstance) {
+               return createAssetInstanceArtifact(AssetType.service, theAssetId, theInstance);
+       }
+
+       public ArtifactUploadAction createAssetArtifact(AssetType theAssetType, UUID theAssetId) {
+               return new ArtifactUploadAction()
+                                                                       .ofAsset(theAssetType, theAssetId);
+       }
+       
+       public ArtifactUploadAction createAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance) {
+               return new ArtifactUploadAction()
+                                                                       .ofAssetInstance(theAssetType, theAssetId, theInstance);
+       }
+
+       public ArtifactUpdateAction updateResourceArtifact(UUID theAssetId, JSONObject theArtifactInfo) {
+               return updateAssetArtifact(AssetType.resource, theAssetId, theArtifactInfo);
+       }
+       
+       public ArtifactUpdateAction updateResourceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
+               return updateAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactInfo);
+       }
+       
+       public ArtifactUpdateAction updateServiceArtifact(UUID theAssetId, JSONObject theArtifactInfo) {
+               return updateAssetArtifact(AssetType.service, theAssetId, theArtifactInfo);
+       }
+       
+       public ArtifactUpdateAction updateServiceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
+               return updateAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactInfo);
+       }
+
+       public ArtifactUpdateAction updateAssetArtifact(AssetType theAssetType, UUID theAssetId, JSONObject theArtifactInfo) {
+               return new ArtifactUpdateAction(theArtifactInfo)
+                                                                       .ofAsset(theAssetType, theAssetId);
+       }
+       
+       public ArtifactUpdateAction updateAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
+               return new ArtifactUpdateAction(theArtifactInfo)
+                                                                       .ofAssetInstance(theAssetType, theAssetId, theInstance);
+       }
+
+       public ArtifactDeleteAction deleteResourceArtifact(UUID theAssetId, UUID theArtifactId) {
+               return deleteAssetArtifact(AssetType.resource, theAssetId, theArtifactId);
+       }
+       
+       public ArtifactDeleteAction deleteResourceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) {
+               return deleteAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId);
+       }
+       
+       public ArtifactDeleteAction deleteServiceArtifact(UUID theAssetId, UUID theArtifactId) {
+               return deleteAssetArtifact(AssetType.service, theAssetId, theArtifactId);
+       }
+       
+       public ArtifactDeleteAction deleteServiceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) {
+               return deleteAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId);
+       }
+
+       public ArtifactDeleteAction deleteAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) {
+               return new ArtifactDeleteAction(theArtifactId)
+                                                                       .ofAsset(theAssetType, theAssetId);
+       }
+       
+       public ArtifactDeleteAction deleteAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId) {
+               return new ArtifactDeleteAction(theArtifactId)
+                                                                       .ofAssetInstance(theAssetType, theAssetId, theInstance);
+       }
+
+       
+       public abstract class ASDCAction<A extends ASDCAction<A, T>, T> implements Action<T> { 
+
+               protected JSONObject    info;                           //info passed to asdc as request body
+               protected String                        operatorId;             //uid of the user performing the action: only required in the updatr
+
+               protected ASDCAction(JSONObject theInfo) {
+                       this.info = theInfo;
+               }
+               
+               protected abstract A self(); 
+
+               protected ASDC asdc() {
+                       return ASDC.this;
+               }
+       
+               protected A withInfo(JSONObject theInfo) {
+                       merge(this.info, theInfo);
+                       return self();
+               }
+       
+               public A with(String theProperty, Object theValue) {
+                       info.put(theProperty, theValue);
+                       return self();
+               }
+
+               public A withOperator(String theOperator) {
+                       this.operatorId = theOperator;
+                       return self();                  
+               }
+               
+               protected abstract String[] mandatoryInfoEntries();
+       
+               protected void checkOperatorId() {
+                       if (this.operatorId == null) {
+                               throw new IllegalStateException("No operator id was provided");
+                       }
+               }
+
+               protected void checkMandatoryInfo() {
+                       for (String field: mandatoryInfoEntries()) {
+                               if (!info.has(field))                   
+                                       throw new IllegalStateException("No '" + field + "' was provided");
+                       }
+               }
+               
+               protected void checkMandatory() {
+                       checkOperatorId();
+                       checkMandatoryInfo();
+               }
+       }
+
+       protected static final String[] artifactMandatoryEntries = new String[] {};
+
+       /**
+   * We use teh same API to operate on artifacts attached to assets or to their instances
+        */
+       public abstract class ASDCArtifactAction<A extends ASDCArtifactAction<A>> extends ASDCAction<A, JSONObject> {
+
+               protected AssetType             assetType;
+               protected UUID                          assetId;
+               protected String                        assetInstance;
+
+               protected ASDCArtifactAction(JSONObject theInfo) {
+                       super(theInfo);
+               }
+               
+               protected A ofAsset(AssetType theAssetType, UUID theAssetId) {
+                       this.assetType = theAssetType;
+                       this.assetId = theAssetId;
+                       return self();                  
+               }
+               
+               protected A ofAssetInstance(AssetType theAssetType, UUID theAssetId, String theInstance) {
+                       this.assetType = theAssetType;
+                       this.assetId = theAssetId;
+                       this.assetInstance = theInstance;
+                       return self();                  
+               }
+               
+               protected String normalizeInstanceName(String theName) {
+                       return StringUtils.removePattern(theName, "[ \\.\\-]+").toLowerCase();
+               }
+               
+               protected String[] mandatoryInfoEntries() {
+                       return ASDC.this.artifactMandatoryEntries;
+               }
+
+               protected String ref(UUID theArtifactId) {
+                       return (this.assetInstance == null) ?
+                                                               refAssetArtifact(this.assetType, this.assetId, theArtifactId) :
+                                                               refAssetInstanceArtifact(this.assetType, this.assetId, normalizeInstanceName(this.assetInstance), theArtifactId);
+               }
+       } 
+
+       protected static final String[] uploadMandatoryEntries = new String[] { "artifactName",
+                                                                                                                                                                                                                                                                                                        "artifactType",
+                                                                                                                                                                                                                                                                                                        "artifactGroupType", 
+                                                                                                                                                                                                                                                                                                        "artifactLabel",
+                                                                                                                                                                                                                                                                                                        "description",
+                                                                                                                                                                                                                                                                                                        "payloadData" };
+
+       public class ArtifactUploadAction extends ASDCArtifactAction<ArtifactUploadAction> {
+               
+               protected ArtifactUploadAction() {
+                       super(new JSONObject());
+               }
+
+               protected ArtifactUploadAction self() {
+                       return this;
+               }
+               
+               public ArtifactUploadAction withContent(byte[] theContent) {
+                       return with("payloadData", Base64Utils.encodeToString(theContent));
+               }
+
+               public ArtifactUploadAction withContent(File theFile) throws IOException {
+                       return withContent(FileUtils.readFileToByteArray(theFile));
+               }
+
+               public ArtifactUploadAction withLabel(String theLabel) {
+                       return with("artifactLabel", theLabel);
+               }
+               
+               public ArtifactUploadAction withName(String theName) {
+                       return with("artifactName", theName);
+               }
+               
+               public ArtifactUploadAction withDisplayName(String theName) {
+                       return with("artifactDisplayName", theName);
+               }
+
+               public ArtifactUploadAction withType(ArtifactType theType) {
+                       return with("artifactType", theType.toString());
+               }
+
+               public ArtifactUploadAction withGroupType(ArtifactGroupType theGroupType) {
+                       return with("artifactGroupType", theGroupType.toString());
+               }
+
+               public ArtifactUploadAction withDescription(String theDescription) {
+                       return with("description", theDescription);
+               }
+               
+               protected String[] mandatoryInfoEntries() {
+                       return ASDC.this.uploadMandatoryEntries;
+               }
+
+               public Future<JSONObject> execute() {
+                       checkMandatory();
+                       return ASDC.this.post(ref(null),
+                                                                                                               (headers) -> prepareHeaders(headers)
+                                                                                                                                                                       .header("USER_ID", this.operatorId),
+                                                                                                               this.info);
+               }
+       }
+
+       protected static final String[] updateMandatoryEntries = new String[] { "artifactName",
+                                                                                                                                                                                                                                                                                                        "artifactType",
+                                                                                                                                                                                                                                                                                                        "artifactGroupType", 
+                                                                                                                                                                                                                                                                                                        "artifactLabel",
+                                                                                                                                                                                                                                                                                                        "description",
+                                                                                                                                                                                                                                                                                                        "payloadData" };
+
+       /**
+        * In its current form the update relies on a previous artifact retrieval. One cannot build an update from scratch.
+        * The label, tye and group type must be submitted but cannot be updated
+        */
+       public class ArtifactUpdateAction extends ASDCArtifactAction<ArtifactUpdateAction> {
+
+               
+               protected ArtifactUpdateAction(JSONObject theInfo) {
+                       super(theInfo);
+               }
+               
+               protected ArtifactUpdateAction self() {
+                       return this;
+               }
+               
+               public ArtifactUpdateAction withContent(byte[] theContent) {
+                       return with("payloadData", Base64Utils.encodeToString(theContent));
+               }
+
+               public ArtifactUpdateAction withContent(File theFile) throws IOException {
+                       return withContent(FileUtils.readFileToByteArray(theFile));
+               }
+
+               public ArtifactUpdateAction withDescription(String theDescription) {
+                       return with("description", theDescription);
+               }
+               
+               public ArtifactUpdateAction withName(String theName) {
+                       return with("artifactName", theName);
+               }
+               
+               protected String[] mandatoryInfoEntries() {
+                       return ASDC.this.updateMandatoryEntries;
+               }
+
+               /* The json object originates (normally) from a get so it will have entries we need to cleanup */
+               protected void cleanupInfoEntries() {
+                       this.info.remove("artifactChecksum");
+                       this.info.remove("artifactUUID");
+                       this.info.remove("artifactVersion");
+                       this.info.remove("artifactURL");
+                       this.info.remove("artifactDescription");
+               }
+               
+               public Future<JSONObject> execute() {
+                       UUID artifactUUID = UUID.fromString(this.info.getString("artifactUUID"));
+                       checkMandatory();
+                       cleanupInfoEntries();
+                       return ASDC.this.post(ref(artifactUUID),
+                                                                                                               (headers) -> prepareHeaders(headers)
+                                                                                                                                                                       .header("USER_ID", this.operatorId),
+                                                                                                               this.info);
+               }
+       }
+
+       public class ArtifactDeleteAction extends ASDCArtifactAction<ArtifactDeleteAction> {
+
+               private UUID            artifactId;
+               
+               protected ArtifactDeleteAction(UUID theArtifactId) {
+                       super(null);
+                       this.artifactId = theArtifactId;
+               }
+               
+               protected ArtifactDeleteAction self() {
+                       return this;
+               }
+               
+               public Future<JSONObject> execute() {
+                       checkMandatory();
+                       return ASDC.this.delete(ref(this.artifactId),
+                                                                                                                 (headers) -> prepareHeaders(headers)
+                                                                                                                                                                       .header("USER_ID", this.operatorId));
+               }
+       }
+
+
+
+
+       public VFCMTCreateAction createVFCMT() {
+               return new VFCMTCreateAction();
+       }
+       
+       protected static final String[] vfcmtMandatoryEntries = new String[] { "name",
+                                                                                                                                                                                                                                                                                                "vendorName",
+                                                                                                                                                                                                                                                                                                "vendorRelease",
+                                                                                                                                                                                                                                                                                                "contactId" };
+
+
+       public class VFCMTCreateAction extends ASDCAction<VFCMTCreateAction, JSONObject> {
+
+               protected VFCMTCreateAction() {
+
+                       super(new JSONObject());
+                       this
+                               .with("resourceType", "VFCMT")
+                               .with("category", "Template")
+                               .with("subcategory", "Monitoring Template")
+                               .with("icon", "defaulticon");
+               }
+               
+               protected VFCMTCreateAction self() {
+                       return this;
+               }
+
+               public VFCMTCreateAction withName(String theName) {
+                       return with("name", theName);
+               }
+
+               public VFCMTCreateAction withDescription(String theDescription) {
+                       return with("description", theDescription);
+               }
+               
+               public VFCMTCreateAction withVendorName(String theVendorName) {
+                       return with("vendorName", theVendorName);
+               }
+               
+               public VFCMTCreateAction withVendorRelease(String theVendorRelease) {
+                       return with("vendorRelease", theVendorRelease);
+               }
+               
+               public VFCMTCreateAction withTags(String... theTags) {
+                       for (String tag: theTags)
+                               this.info.append("tags", tag);
+                       return this;                    
+               }
+               
+               public VFCMTCreateAction withIcon(String theIcon) {
+                       return with("icon", theIcon);
+               }
+               
+               protected String[] mandatoryInfoEntries() {
+                       return ASDC.this.vfcmtMandatoryEntries;
+               }
+               
+               public VFCMTCreateAction withContact(String theContact) {
+                       return with("contactId", theContact);
+               }
+               
+               public Future<JSONObject> execute() {
+               
+                       this.info.putOnce("contactId", this.operatorId);        
+                       this.info.append("tags", info.optString("name"));
+                       checkMandatory();
+                       return ASDC.this.post(refAssets(AssetType.resource),
+                                                                                                               (headers) -> prepareHeaders(headers)
+                                                                                                                                                                       .header("USER_ID", this.operatorId),
+                                                                                                               this.info);
+               }
+
+       }
+       
+
+       public VFCreateAction createVF() {
+               return new VFCreateAction();
+       }
+       
+       protected static final String[] vfMandatoryEntries = new String[] {"category",
+                                                                                                                                                                                                                                                                                "subcategory",
+                                                                                                                                                                                                                                                                                "name",
+                                                                                                                                                                                                                                                                                "vendorName",
+                                                                                                                                                                                                                                                                                "vendorRelease",
+                                                                                                                                                                                                                                                                                "contactId" };
+
+
+
+       public class VFCreateAction extends ASDCAction<VFCreateAction, JSONObject> {
+
+               protected VFCreateAction() {
+
+                       super(new JSONObject());
+                       this
+                               .with("resourceType", "VF")
+                               .with("icon", "defaulticon");
+               }
+               
+               protected VFCreateAction self() {
+                       return this;
+               }
+
+               public VFCreateAction withCategory(String theCategory) {
+                       return with("category", theCategory);
+               }
+
+               public VFCreateAction withSubCategory(String theSubCategory) {
+                       return with("subcategory", theSubCategory);
+               }
+
+               public VFCreateAction withName(String theName) {
+                       return with("name", theName);
+               }
+
+               public VFCreateAction withDescription(String theDescription) {
+                       return with("description", theDescription);
+               }
+               
+               public VFCreateAction withVendorName(String theVendorName) {
+                       return with("vendorName", theVendorName);
+               }
+               
+               public VFCreateAction withVendorRelease(String theVendorRelease) {
+                       return with("vendorRelease", theVendorRelease);
+               }
+               
+               public VFCreateAction withTags(String... theTags) {
+                       for (String tag: theTags)
+                               this.info.append("tags", tag);
+                       return this;                    
+               }
+               
+               public VFCreateAction withIcon(String theIcon) {
+                       return with("icon", theIcon);
+               }
+               
+               protected String[] mandatoryInfoEntries() {
+                       return ASDC.this.vfMandatoryEntries;
+               }
+               
+               public VFCreateAction withContact(String theContact) {
+                       return with("contactId", theContact);
+               }
+               
+               public Future<JSONObject> execute() {
+               
+                       this.info.putOnce("contactId", this.operatorId);        
+                       this.info.append("tags", info.optString("name"));
+                       checkMandatory();
+                       return ASDC.this.post(refAssets(AssetType.resource),
+                                                                                                               (headers) -> prepareHeaders(headers)
+                                                                                                                                                                       .header("USER_ID", this.operatorId),
+                                                                                                               this.info);
+               }
+
+       }
+
+
+       public static JSONObject merge(JSONObject theOriginal, JSONObject thePatch) {
+               for (String key: thePatch.keySet()) {
+                       if (!theOriginal.has(key))
+                               theOriginal.put(key, thePatch.get(key));
+               }
+               return theOriginal;
+       }
+
+       protected URI refUri(String theRef) {
+               try {
+                       return new URI(this.rootUri + theRef);
+               }
+               catch(URISyntaxException urisx) {
+                       throw new UncheckedIOException(new IOException(urisx));
+               }
+       }
+
+       private HttpHeaders prepareHeaders() {
+               HttpHeaders headers = new HttpHeaders();
+               headers.add(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes()));
+               headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
+               headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE);
+               headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
+               headers.add("X-ECOMP-InstanceID", this.instanceId);
+
+               return headers;
+       }
+
+       private RequestEntity.HeadersBuilder prepareHeaders(RequestEntity.HeadersBuilder theBuilder) {
+               return theBuilder
+                       .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes()))
+                       .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
+                       .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE)
+                       .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
+                       .header("X-ECOMP-InstanceID", this.instanceId);
+       }
+
+       public <T> Future<T> fetch(String theRef, Class<T> theContentType) {
+               return exchange(theRef, HttpMethod.GET, new HttpEntity(prepareHeaders()), theContentType);
+       }
+
+       public Future<JSONObject> post(String theRef, JSONObject thePost) {
+               return exchange(theRef, HttpMethod.POST, new HttpEntity<JSONObject>(thePost, prepareHeaders()), JSONObject.class);
+       }
+       
+       public Future<JSONObject> post(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder, JSONObject thePost) {
+               RequestEntity.BodyBuilder builder = RequestEntity.post(refUri(theRef));
+               theHeadersBuilder.apply(builder);
+
+               return exchange(theRef, HttpMethod.POST, builder.body(thePost), JSONObject.class);
+       }
+       
+       public Future<JSONObject> delete(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder) {
+
+               RequestEntity.HeadersBuilder builder = RequestEntity.delete(refUri(theRef));
+               theHeadersBuilder.apply(builder);
+
+               return exchange(theRef, HttpMethod.DELETE, builder.build(), JSONObject.class);
+       }
+       
+       public <T> Future<T> exchange(String theRef, HttpMethod theMethod, HttpEntity theRequest, Class<T> theResponseType) {
+               
+               AsyncRestTemplate restTemplate = new AsyncRestTemplate();
+
+               List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
+               converters.add(0, new JSONHttpMessageConverter());
+               restTemplate.setMessageConverters(converters);
+
+               restTemplate.setInterceptors(Collections.singletonList(new ContentMD5Interceptor()));
+/*
+               restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
+                                                                                       public boolean  hasError(ClientHttpResponse theResponse) throws IOException {
+                                                                                               if (404 == theResponse.getRawStatusCode()) {
+                                                                                                       System.out.println("Found a 404 !");
+                                                                                                       return false;
+                                                                                               }
+                                                                                               return super.hasError(theResponse);
+                                                                                       }
+
+                                                                                       protected byte[] getResponseBody(ClientHttpResponse theResponse) {
+                                                                                               if (404 == theResponse.getRawStatusCode()) {
+                                                                                                       return "[]".getBytes();
+                                                                                               }
+                                                                                               return super.getResponseBody(theResponse);
+                                                                                       }
+                                                                       });
+*/     
+               //ResponseEntity<T> response = null;
+               ASDCFuture<T> result = new ASDCFuture<T>();
+               String uri = this.rootUri + theRef;
+               try {
+                       restTemplate
+                               .exchange(uri, theMethod, theRequest, theResponseType)
+                                       .addCallback(result.callback);
+               }
+               catch (RestClientException rcx) {
+                       log.log(Level.WARNING, "Failed to fetch " + uri, rcx);
+                       return Futures.failedFuture(rcx);
+               }
+               catch (Exception x) {
+                       log.log(Level.WARNING, "Failed to fetch " + uri, x);
+                       return Futures.failedFuture(x);
+               }
+        
+               return result;
+       }
+
+
+
+       public class ASDCFuture<T>
+                                                                               extends Futures.BasicFuture<T> {
+
+               private boolean http404toEmpty = false;
+
+               ASDCFuture() {
+               }
+
+               public ASDCFuture setHttp404ToEmpty(boolean doEmpty) {
+                       this.http404toEmpty = doEmpty;
+                       return this;
+               }
+
+               ListenableFutureCallback<ResponseEntity<T>> callback = new ListenableFutureCallback<ResponseEntity<T>>() {
+
+                       public void     onSuccess(ResponseEntity<T> theResult) {
+                               ASDCFuture.this.result(theResult.getBody());
+                       }
+
+                       public void     onFailure(Throwable theError) {
+                               if (theError instanceof HttpClientErrorException) {
+                               //      if (theError.getRawStatusCode() == 404 && this.http404toEmpty)
+                               //              ASDCFuture.this.result(); //th eresult is of type T ...
+                               //      else
+                                               ASDCFuture.this.cause(new ASDCException((HttpClientErrorException)theError));
+                               }
+                               else {
+                                       ASDCFuture.this.cause(theError);
+                               }
+                       }
+               };
+
+       }
+
+       public class ContentMD5Interceptor implements AsyncClientHttpRequestInterceptor {
+
+    @Override
+    public ListenableFuture<ClientHttpResponse> intercept(
+            HttpRequest theRequest, byte[] theBody, AsyncClientHttpRequestExecution theExecution)
+                                                                                                                                                                                                                                                                                                               throws IOException {
+                               if (HttpMethod.POST == theRequest.getMethod()) {
+               HttpHeaders headers = theRequest.getHeaders();
+             headers.add("Content-MD5", Base64Utils.encodeToString(
+                                                                                                                                                               //DigestUtils.md5Digest(theBody)));
+                                                                                                                                                               DigestUtils.md5Hex(theBody).getBytes()));
+                                                                                                                                                                       
+                               }
+         return theExecution.executeAsync(theRequest, theBody);
+    }
+       }
+       
+//amdocs: "http://dcaedt:dcae123@135.16.121.89:8080#demo"));
+       public static void main(String[] theArgs) throws Exception {
+
+               CommandLineParser parser = new BasicParser();
+               
+               Options options = new Options();
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("target")
+                                                                                                                       .withLongOpt("target")
+                               .withDescription("target asdc system")
+                                                                                                                       .hasArg()
+                                                                                                                       .isRequired()
+                                                                                                                       .create('t') );
+                       
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("rootPath")
+                                                                                                                       .withLongOpt("rootpath")
+                               .withDescription("asdc rootpath")
+                                                                                                                       .hasArg()
+                                                                                                                       .isRequired()
+                                                                                                                       .create('r') );
+
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("action")
+                                                                                                                       .withLongOpt("action")
+                              .withDescription("one of: list, get, getartifact, checkin, checkout")
+                                                                                                                       .hasArg()
+                                                                                                                       .isRequired()
+                                                                                                                       .create('a') );
+
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("assetType")
+                                                                                                                       .withLongOpt("assetType")
+                               .withDescription("one of resource, service, product")
+                                                                                                                       .hasArg()
+                                                                                                                       .isRequired()
+                                                                                                                       .create('k') ); //k for 'kind' ..
+
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("assetId")
+                                                                                                                       .withLongOpt("assetId")
+                               .withDescription("asset uuid")
+                                                                                                                       .hasArg()
+                                                                                                                       .create('u') ); //u for 'uuid'
+
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("artifactId")
+                                                                                                                       .withLongOpt("artifactId")
+                               .withDescription("artifact uuid")
+                                                                                                                       .hasArg()
+                                                                                                                       .create('s') ); //s for 'stuff'
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("instance")
+                                                                                                                       .withLongOpt("instance")
+                               .withDescription("asset instance name")
+                                                                                                                       .hasArg()
+                                                                                                                       .create('i') );
+               options.addOption(OptionBuilder
+                                                                                                                 .withArgName("listFilter")
+                                                                                                                       .withLongOpt("listFilter")
+                               .withDescription("filter for list operations")
+                                                                                                                       .hasArg()
+                                                                                                                       .create('f') ); //u for 'uuid'
+
+               CommandLine line = null;
+               try {
+               line = parser.parse(options, theArgs);
+               }
+               catch(ParseException exp) {
+                       System.err.println(exp.getMessage());
+                       new HelpFormatter().printHelp("asdc", options);
+                       return;
+               }
+
+               ASDC asdc = new ASDC();
+               asdc.setUri(new URI(line.getOptionValue("target")));
+               asdc.setRootPath(line.getOptionValue("rootpath"));
+
+               String instance = line.getOptionValue("instance");
+               String action = line.getOptionValue("action");
+               if (action.equals("list")) {
+                       JSONObject filterInfo = new JSONObject(
+                                                                                                                                                       line.hasOption("listFilter") ?
+                                                                                                                                                               line.getOptionValue("listFilter") : "{}");
+                       JSONArray assets = 
+                               asdc.getAssets(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), JSONArray.class,
+                                                                                        filterInfo.optString("category", null), filterInfo.optString("subCategory", null))
+                                               .waitForResult();
+                       for (int i = 0; i < assets.length(); i++) {
+                               System.out.println("> " + assets.getJSONObject(i).toString(2));
+                       }
+               }
+               else if (action.equals("get")) {
+                       System.out.println(
+                               asdc.getAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
+                                                                                       UUID.fromString(line.getOptionValue("assetId")),
+                                                                                       JSONObject.class)
+                                               .waitForResult()
+                                               .toString(2)
+                       );
+               }
+               else if (action.equals("getartifact")) {
+                       if (instance == null) {
+                               System.out.println(
+                                       asdc.getAssetArtifact(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
+                                                                                                                               UUID.fromString(line.getOptionValue("assetId")),
+                                                                                                                               UUID.fromString(line.getOptionValue("artifactId")),
+                                                                                                                               String.class)
+                                                       .waitForResult()
+                               );
+                       }
+                       else {
+                               System.out.println(
+                                       asdc.getAssetInstanceArtifact(
+                                                                                                                               ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
+                                                                                                                               UUID.fromString(line.getOptionValue("assetId")),
+                                                                                                                               instance,
+                                                                                                                               UUID.fromString(line.getOptionValue("artifactId")),
+                                                                                                                               String.class)
+                                                       .waitForResult()
+                               );
+                       }
+               }
+               else if (action.equals("checkin")) {
+                       System.out.println(
+                                       asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
+                                                                                                       UUID.fromString(line.getOptionValue("assetId")),
+                                                                                                       ASDC.LifecycleState.Checkin,
+                                                                                                       "Admin",
+                                                                                                       "cli op")
+                                                       .waitForResult()
+                       );
+               }
+               else if (action.equals("checkout")) {
+                       System.out.println(
+                                       asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
+                                                                                                       UUID.fromString(line.getOptionValue("assetId")),
+                                                                                                       ASDC.LifecycleState.Checkout,
+                                                                                                       "Admin",
+                                                                                                       "cli op")
+                                                       .waitForResult()
+                       );
+               }
+               else if (action.equals("cleanup")) {
+                       JSONArray resources = asdc.getResources()
+                                                                                                                                       .waitForResult();
+                       System.out.println("Got " + resources.length() + " resources");
+
+
+                       // vfcmt cleanup 
+                       for (int i = 0; i < resources.length(); i++) {
+
+                               JSONObject resource = resources.getJSONObject(i);
+
+                               if (resource.getString("resourceType").equals("VFCMT") &&
+                                               resource.getString("name").contains("test")) {
+
+                                       System.out.println("undocheckout for " + resource.getString("uuid"));
+
+                                       try {
+                                               asdc.cycleAsset(AssetType.resource, UUID.fromString(resource.getString("uuid")), LifecycleState.undocheckout, "sj2381", null)
+                                                       .waitForResult();
+                                       }
+                                       catch (Exception x) {
+                                               System.out.println("** " + x);
+                                       }
+                               }
+                       }
+
+               }
+               else {
+                       try {
+                               System.out.println(
+                                       asdc.createVF()
+                                                       .withInfo(new JSONObject()
+                                                                                                       .put("category", "Generic")
+                                                                                                       .put("subcategory", "Abstract"))
+                                                       .withName("Cognitor")
+                                                       .withDescription("Acumos import 07262017")
+                                                       .withVendorName("AcumosInc")
+                                                       .withVendorRelease("1.0")
+                                                       .withTags("acumos")
+                                                       .withOperator("sj2381")
+                                                       .execute()
+                                                       .waitForResult());
+                       }
+                       catch(Exception x) {
+                               System.out.println("Failed to create VF: " + x);
+                       }
+       }       
+/*
+               else {
+                       UUID cid = UUID.fromString(line.getOptionValue("assetId"));
+                       JSONObject jsonObj = asdc.getResource(cid).waitForResult();
+                       System.out.println(jsonObj);
+               
+                       JSONObject artifactObj = null;
+                       boolean flag = false;
+
+                       JSONArray resObj = jsonObj.optJSONArray("artifacts");
+                       if(resObj != null) {
+                               for(int i=0; i< resObj.length(); i++) {
+                                       artifactObj = (JSONObject) resObj.get(i);
+                                       System.out.println(artifactObj);
+                                       if(artifactObj.get("artifactName").equals("superposition.yml")) {
+                                               asdc.updateResourceArtifact(cid, artifactObj)
+                                                       .withContent("{}".getBytes())
+                                                       .withOperator("sj2381")
+                               //                      .withLabel("Superposition")
+                               //                      .withType(ArtifactType.DCAE_TOSCA)
+                               //                      .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                                       .withDescription(" serban asdc api test")
+                                                       .execute()
+                                                       .waitForResult();
+                                                       flag = true;
+                                       }
+                               }
+                       }
+
+                       if(!flag) {
+                                       asdc.createResourceArtifact(cid)
+                                                       .withName("superposition.yml")
+                                                       .withDisplayName("composition")
+                                                       .withContent("{}".getBytes())
+                                                       .withOperator("sj2381")
+                                                       .withLabel("Superposition")
+                                                       .withType(ArtifactType.DCAE_TOSCA)
+                                                       .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                                       .withDescription(" serban asdc api test")
+                                                       .execute()
+                                                       .waitForResult();
+                       }
+
+                       System.out.println(">>> " + 
+                               asdc.checkinResource(cid, "sj2381", "done")
+                                               .waitForResult());
+
+               }
+*/
+/*
+               System.out.println(
+               asdc.deleteServiceInstanceArtifact(UUID.fromString("b8c40b18-a295-4f7d-905f-4ce18f939f9c"),
+                                                                                                                                                        "vMOG_for_DCAEDT 1",
+                                                                                                                                                        UUID.fromString("0992b5a9-75e0-4f0f-994c-8c7be6616e13"))
+                                                               .withOperator("sj2381")
+                                                               .execute()
+                                                               .waitForResult());
+*/
+
+/*
+               JSONArray services = asdc.getServices()
+//("DCAE Component", null)
+//                                                                                                                             .waitForResult();
+//             System.out.println("Got " + services.length() + " services");
+//             System.out.println(services.toString(2));
+
+               for (int i = 0; i < services.length(); i++) {
+//                     if (services.getJSONObject(i).getString("name").equals("DCAEDT_vMOG_Srvc3")) {
+//                     if (services.getJSONObject(i).getString("name").equals("MonicaforBP")) {
+                               UUID serviceId = UUID.fromString(services.getJSONObject(i).getString("uuid"));
+
+                               System.out.println("Service " + serviceId);
+
+                               if (theArgs.length > 1 && !theArgs[1].equals(serviceId.toString()))
+                                       continue;
+       
+                               JSONObject service = null;
+                               try {
+                                       service = asdc.getService(serviceId)
+                                                                                                                                       .waitForResult();
+                               }
+                               catch(Exception x) {
+                                       System.out.println(x);
+                                       continue;
+                               }
+                               System.out.println("Service details: " + service);
+                       
+                               asdc.checkinService(serviceId, "sj2381", "ready for update")
+                                                       .waitForResult();
+       
+
+                               JSONArray instances = service.optJSONArray("resources");
+                               if (instances != null) {
+                                       JSONObject instance = instances.getJSONObject(0);
+                                       try {
+*/
+                                               //System.out.println("Found instances, processing artifact for " + instance);
+
+/*
+                                               System.out.println(
+                                               asdc.createServiceInstanceArtifact(UUID.fromString(services.getJSONObject(i).getString("uuid")),
+                                                                                                                                                                                                       instance.getString("resourceInstanceName"))
+                                                               .withName("test.yaml")
+                                                               .withDisplayName("artificial")
+                                                               .withLabel("artificial")
+                                                               .withDescription("serban asdc api test")
+                                                               .withContent(new File(theArgs[theArgs.length-1]))
+                                                               //.withType(ArtifactType.DCAE_TOSCA)
+                                                               //.withType(ArtifactType.HEAT_ARTIFACT)
+                                                               .withType(ArtifactType.DCAE_INVENTORY_BLUEPRINT)
+                                                               .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                                               .withOperator("sj2381")
+                                                               .execute()
+                                                               .waitForResult());
+                                                       asdc.deleteServiceInstanceArtifact(UUID.fromString(services.getJSONObject(i).getString("uuid")),
+                                                                                                                                                                                                instance.getString("resourceInstanceName"),
+                                                                                                                                                                                                UUID.fromString(
+                                                                                                                                                                                                       instance.getJSONArray("artifacts").getJSONObject(0).getString("artifactUUID")))
+                                                               .withOperator("sj2381")
+                                                               .execute()
+                                                               .waitForResult());
+*/
+
+/*
+                                       }
+                                       catch(Exception x) {
+                                               System.out.println("Failed to create resource instance artifact" + x);
+                                               return;
+                                       }
+//                             }
+                       }
+               }       
+*/
+
+
+
+//             List resources = asdc.getResources(List.class, "DCAE Component", "Database")
+//                                                                                                                             .waitForResult();
+//             System.out.println(resources.toString());
+
+
+//             String artifact = asdc.getResourceArtifact(UUID.fromString(theArgs[1]),UUID.fromString(theArgs[2]),String.class)
+//                                                                                                             .waitForResult();
+//             System.out.println(artifact);
+
+//             System.out.println(
+//                     asdc.checkinService(UUID.fromString(theArgs[1]), "sj2381", "testing")
+//                             .waitForResult());
+
+//             System.out.println(
+//                     asdc.checkinService(UUID.fromString(theArgs[1]), "sj2381", "tested")
+//                             .waitForResult());
+
+/*
+               try {
+                       System.out.println(
+                               asdc.createResourceArtifact(UUID.fromString(theArgs[1]))
+                                               .withName("test.yml")
+                                               .withDisplayName("test")
+                                               .withLabel("test")
+                                               .withDescription("serban asdc api test")
+                                               .withContent(new File(theArgs[2]))
+                                               .withType(ArtifactType.DCAE_TOSCA)
+                                               .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                               .withOperator("sj2381")
+                                               .execute()
+                                               .waitForResult());
+               }
+               catch(Exception x) {
+                       System.out.println("Failed to create asset " + x);
+                       return;
+               }       
+*/
+
+/*
+               JSONObject resource = asdc.getResource(UUID.fromString(theArgs[1]), JSONObject.class)
+                                                                                                                               .waitForResult();
+               System.out.println(resource.toString(2));
+               JSONArray artifacts = resource.getJSONArray("artifacts");
+               JSONObject artifact = artifacts.getJSONObject(0);
+*/
+
+
+/*             
+               byte[] archive = asdc.getResourceArchive(UUID.fromString(theArgs[1]))
+                                                                                                       .waitForResult();
+               FileUtils.writeByteArrayToFile(new File("archive.jar"), archive);       
+*/
+
+/*
+               String artifactInfo = asdc.getResourceArtifact(
+                                                                                                                                                                               UUID.fromString(theArgs[1]),
+                                                                                                                                                                               UUID.fromString(artifacts.getJSONObject(0).getString("artifactUUID")),
+                                                                                                                                                                               String.class)
+                                                                                                               .waitForResult();
+               System.out.println(artifactInfo);
+*/
+
+/*
+               System.out.println(
+                               asdc.fetch(
+                                       asdc.refAssetArtifact(AssetType.resource, UUID.fromString(theArgs[1]), UUID.fromString(artifact.getString("artifactUUID"))), JSONObject.class)
+                                       .waitForResult()
+                                       .toString(2));
+*/
+
+/*
+               try {
+                       System.out.println(
+                               asdc.updateResourceArtifact(UUID.fromString(theArgs[1]), artifact)
+                                               .withDescription("serban asdc api test update")
+                                               .withContent(new File(theArgs[3]))
+                                               .withLabel("test")
+                                               .withOperator("sj2381")
+                                               .execute()
+                                               .waitForResult());
+               }
+               catch(Exception x) {
+                       System.out.println("Failed to update asset " + x);
+                       return;
+               }
+*/
+
+
+/*
+               try {
+                       asdc.deleteResourceArtifact(UUID.fromString(theArgs[1]),
+                                                                                                                                       UUID.fromString(artifacts.getJSONObject(0).getString("artifactUUID")))
+                                       .withOperator("sj2381")
+                                       .execute()
+                                       .waitForResult();
+               }
+               catch(Exception x) {
+                       System.out.println("Failed to delete asset artifact " + x);
+               }       
+*/
+
+/*
+       try {
+               JSONObject artifact = artifacts.getJSONObject(0);
+
+               System.out.println(
+                       asdc.updateResourceArtifact(UUID.fromString(theArgs[1]),
+                                                                                                                                 UUID.fromString(artifacts.getJSONObject(0).getString("artifactUUID")))
+                                               .withName(artifact.getString("artifactName"))
+                                               .withDescription("serban asdc api test update")
+                                               .withContent(new File(theArgs[2]))
+                                               .withGroupType(ArtifactGroupType.DEPLOYMENT)
+                                               .withLabel("test")
+                                               .withType(ArtifactType.valueOf(artifact.getString("artifactType")))
+                                               .withATTContact("sj2381")
+                                               .post()
+                                               .waitForResult());
+       }
+       catch(Exception x) {
+               System.out.println("Failed to update asset artifact " + x);
+       }       
+*/
+/*
+       try {
+               System.out.println(
+                       asdc.createVFCMT()
+                                                       .withName("SB4.5")
+                                                       .withDescription("All mountain")
+                                                       .withVendorName("Yeti")
+                                                       .withVendorRelease("1.0")
+                                                       .withTags("MTB", "FS")
+                                                       .withOperator("sj2381")
+                                                       .execute()
+                                                       .waitForResult());
+       }
+       catch(Exception x) {
+               System.out.println("Failed to create VFCMT: " + x);
+       }       
+*/
+/*
+               asdc.updateAssetArtifact(AssetType.resource, UUID.fromString(theArgs[1]), UUID.fromString(theArgs[2]))
+                                       .withDescription("serban asdc api test")
+                                       .post();        
+*/
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDCException.java b/gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/sdc/ASDCException.java
new file mode 100644 (file)
index 0000000..eb5892d
--- /dev/null
@@ -0,0 +1,80 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.adapter.onap.sdc;
+
+import java.util.Arrays;
+
+import org.springframework.web.client.HttpClientErrorException;
+
+import org.json.JSONObject;
+import org.json.JSONArray;
+
+/** */
+public class ASDCException extends Exception {
+
+       private static final String[] ERROR_CLASSES = new String[] { "policyException", "serviceException" };
+
+       private JSONObject content;
+
+       public ASDCException(HttpClientErrorException theError) {
+               super(theError);
+
+               String body = theError.getResponseBodyAsString();
+               if (body != null) {
+                       JSONObject error = new JSONObject(body)
+                                                                                                       .getJSONObject("requestError");
+                       if (error != null) {
+                               this.content = Arrays.stream(ERROR_CLASSES)
+                                                                                                                       .map(c -> error.optJSONObject(c))
+                                                                                                                       .filter(x -> x != null)
+                                                                                                                       .findFirst()
+                                                                                                                       .orElse(null);
+                       }
+               }
+       }
+
+       public String getASDCMessageId() {
+               return this.content == null ? "" : this.content.optString("messageId");
+       }
+
+       public String getASDCMessage() {
+               if (this.content == null)
+                       return "";
+
+               String msg = content.optString("text");
+               if (msg != null) {
+                       JSONArray vars = content.optJSONArray("variables");
+                       if (vars != null) {
+                               for (int i = 0; i < vars.length(); i++) {
+                                       msg = msg.replaceAll("%"+(i+1), vars.optString(i));
+                               }
+                       }
+                       return msg;
+               }
+               else
+                       return "";
+       }
+
+       @Override
+       public String getMessage() {
+               return "ASDC " + getASDCMessageId() + " " + getASDCMessage() + "\n" + super.getMessage();
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/AdapterCondition.java b/gateway/src/main/java/org/acumos/federation/gateway/common/AdapterCondition.java
new file mode 100644 (file)
index 0000000..f4942e1
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.env.Environment;
+
+/**
+ * Bean instantiantion conditional on wether we are running as an adapter
+ */
+public class AdapterCondition implements Condition {
+
+       @Override
+       public boolean matches(ConditionContext theContext, 
+                                                                                                AnnotatedTypeMetadata theMetadata) {
+
+               Environment env = theContext.getEnvironment();
+    return null != env &&
+                                        "adapter".equals(env.getProperty("federated.instance"));
+  }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/FederationClientConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/common/FederationClientConfiguration.java
new file mode 100644 (file)
index 0000000..c44ad0c
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+import org.apache.http.client.HttpClient;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Scope;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+
+@Configuration
+//@PropertySource("classpath:configprops.properties")
+@ConfigurationProperties(prefix = "client")
+public class FederationClientConfiguration extends HttpClientConfiguration {
+
+
+       @Bean
+       @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+       public HttpClient federationClient() {
+               log.debug(EELFLoggerDelegate.debugLogger, "Build federation client");
+               return buildClient();
+       }
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/FederationDataClientConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/common/FederationDataClientConfiguration.java
new file mode 100644 (file)
index 0000000..f0d953e
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+import org.apache.http.client.HttpClient;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Scope;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+
+
+@Configuration
+//@PropertySource("classpath:configprops.properties")
+@ConfigurationProperties(prefix = "cdms.client")
+public class FederationDataClientConfiguration extends HttpClientConfiguration {
+
+
+       @Bean
+       @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+       public HttpClient federationDataClient() {
+               return buildClient();
+       }
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/GatewayCondition.java b/gateway/src/main/java/org/acumos/federation/gateway/common/GatewayCondition.java
new file mode 100644 (file)
index 0000000..a8cab2d
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+import org.springframework.context.annotation.Condition;
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.env.Environment;
+
+/**
+ * Bean instantiantion conditional on wether we are running as a gateway
+ */
+public class GatewayCondition implements Condition {
+
+       @Override
+       public boolean matches(ConditionContext theContext, 
+                                                                                                AnnotatedTypeMetadata theMetadata) {
+
+               Environment env = theContext.getEnvironment();
+    return null != env && "gateway".equals(env.getProperty("federated.instance"));
+  }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/GatewayConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/common/GatewayConfiguration.java
new file mode 100644 (file)
index 0000000..2abe105
--- /dev/null
@@ -0,0 +1,34 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+@EnableConfigurationProperties({FederationClientConfiguration.class,
+                               FederationDataClientConfiguration.class})
+public class GatewayConfiguration {
+
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/GhostAdapterCondition.java b/gateway/src/main/java/org/acumos/federation/gateway/common/GhostAdapterCondition.java
new file mode 100644 (file)
index 0000000..6723c83
--- /dev/null
@@ -0,0 +1,44 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+
+import org.springframework.context.annotation.ConditionContext;
+import org.springframework.core.type.AnnotatedTypeMetadata;
+import org.springframework.core.env.Environment;
+
+/**
+ * Tests if we are in a ghost Adapter setup/profile
+ */
+public class GhostAdapterCondition extends AdapterCondition {
+
+       @Override
+       public boolean matches(ConditionContext theContext,
+                                                                                                AnnotatedTypeMetadata theMetadata) {
+
+               Environment env = theContext.getEnvironment();
+               return super.matches(theContext, theMetadata) &&
+                                                                                                null != env &&
+                                                                                                "ghost".equals(env.getProperty("federated.instance.name"));
+  }
+
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/HttpClientConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/common/HttpClientConfiguration.java
new file mode 100644 (file)
index 0000000..2dfc85c
--- /dev/null
@@ -0,0 +1,291 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Scope;
+import org.springframework.beans.factory.config.ConfigurableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ResourceLoader;
+
+import java.net.URI;
+
+import javax.net.SocketFactory;
+import javax.net.ssl.SSLContext;
+
+import java.security.KeyStore;
+
+import org.apache.http.client.HttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLContextBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+//import org.apache.http.ssl.SSLContexts;
+//import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.conn.ssl.SSLContexts;
+import org.apache.http.conn.ssl.SSLContextBuilder;
+               
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+
+@Configuration
+//@PropertySource("classpath:configprops.properties")
+@ConfigurationProperties(prefix = "client")
+public class HttpClientConfiguration {
+
+       @Autowired
+       private ResourceLoader resourceLoader;
+       
+       protected final EELFLoggerDelegate log =
+                                                                                       EELFLoggerDelegate.getLogger(getClass().getName());
+
+       private String username;
+       private String passwd;
+       private int              poolSize = 10;
+       private SSL              ssl;
+         
+       public String getUsername() { return this.username; }
+       public void     setUsername(String theUsername)
+                                                                                                                               { this.username = theUsername; }
+       
+       public String getPassword() { return this.username; }
+       public void     setPassword(String thePassword)
+                                                                                                                               { this.passwd = thePassword; }
+       
+       public int getPoolSize() { return this.poolSize; }
+       public void     setPoolSize(int thePoolSize)
+                                                                                                                               { this.poolSize = thePoolSize; }
+       
+       public SSL getSSL() { return this.ssl; }
+       public void     setSSL(SSL theSSL)
+                                                                                                                               { this.ssl = theSSL; }
+
+       public static class SSL {
+
+       private String keyStore;
+       private String keyStoreType = "JKS";
+       private String keyStorePasswd;
+       private String keyAlias;
+       private String trustStore;
+       private String trustStoreType = "JKS";
+       private String trustStorePasswd;
+
+         public String getKeyStore() { return this.keyStore; }
+       public void     setKeyStore(String theKeyStore)
+                                                                                                                               { this.keyStore = theKeyStore; }
+         
+         public String getKeyStoreType() { return this.keyStoreType; }
+       public void     setKeyStoreType(String theKeyStoreType)
+                                                                                                                               { this.keyStoreType = theKeyStoreType; }
+
+               public String getKeyStorePassword() { return this.keyStorePasswd; }
+       public void     setKeyStorePassword(String theKeyStorePassword)
+                                                                                                                               { this.keyStorePasswd = theKeyStorePassword; }
+         
+               public String getKeyAlias() { return this.keyAlias; }
+       public void     setKeyAlias(String theKeyAlias)
+                                                                                                                               { this.keyAlias = theKeyAlias; }
+         
+               public String getTrustStore() { return this.trustStore; }
+       public void     setTrustStore(String theTrustStore)
+                                                                                                                               { this.trustStore = theTrustStore; }
+               
+               public String getTrustStoreType() { return this.trustStoreType; }
+       public void     setTrustStoreType(String theTrustStoreType)
+                                                                                                                               { this.trustStoreType = theTrustStoreType; }
+
+               public String getTrustStorePassword() { return this.trustStorePasswd; }
+       public void     setTrustStorePassword(String theTrustStorePassword)
+                                                                                                                       { this.trustStorePasswd = theTrustStorePassword; }
+
+               protected boolean hasKeyStoreInfo() {
+                       return this.keyStore != null &&
+                                                this.keyStoreType != null &&
+                                                this.keyStorePasswd != null;
+               }
+
+               protected boolean hasTrustStoreInfo() {
+                       return this.trustStore != null &&
+                                                this.trustStoreType != null /*&&
+                                                this.trustStorePasswd != null*/;
+               }
+
+               public String toString() {
+                       return new StringBuilder("")    
+                                                       .append("SSL(")
+                                                       .append(this.keyStore)
+                                                       .append(",")
+                                                       .append(this.keyStoreType)
+                                                       .append(",")
+                                                       .append(this.keyAlias)
+                                                       .append("/")
+                                                       .append(this.trustStore)
+                                                       .append(",")
+                                                       .append(this.trustStoreType)
+                                                       .append(")")
+                                                       .toString();
+               }
+       }
+
+       public String toString() {
+               return new StringBuilder("")    
+                                               .append("ClientConfiguration(")
+                                               .append(this.ssl)
+                                               .append(")")
+                                               .toString();
+       }
+
+  public HttpClient buildClient() {
+
+               SSLContext sslContext = null;
+               log.info(EELFLoggerDelegate.debugLogger, "Build HttpClient with " + this);
+
+               if (this.ssl == null) {
+                       log.info(EELFLoggerDelegate.debugLogger, "No ssl config was provided");
+               }
+               else {
+                       KeyStore keyStore = null;
+                       if (this.ssl.hasKeyStoreInfo()) {
+                               try {
+                                       keyStore = KeyStore.getInstance(this.ssl.keyStoreType);
+                                       keyStore.load(this.resourceLoader.getResource(this.ssl.keyStore)
+                                                                                                               .getURL().openStream(),
+                                                                                               //new URI(this.ssl.keyStore).toURL().openStream(),
+                                                                                               this.ssl.keyStorePasswd.toCharArray());
+                                       log.info(EELFLoggerDelegate.debugLogger, "Loaded key store: " + this.ssl.keyStore);
+                               }
+                               catch (Exception x) {
+                                       throw new IllegalStateException(
+                                                                               "Error loading key material", x);
+                               }
+                       }
+
+                       KeyStore trustStore = null;
+                       if (this.ssl.hasTrustStoreInfo()) {
+                               try {
+                                       trustStore = KeyStore.getInstance(this.ssl.trustStoreType);
+                                       trustStore.load(this.resourceLoader.getResource(this.ssl.trustStore)
+                                                                                                                       .getURL().openStream(),
+                                                                                                       //new URI(this.ssl.trustStore).toURL().openStream(),
+                                                                                                       this.ssl.trustStorePasswd.toCharArray());
+                                       log.info(EELFLoggerDelegate.debugLogger, "Loaded trust store: " + this.ssl.trustStore);
+                               }
+                               catch (Exception x) {
+                                       throw new IllegalStateException(
+                                                                               "Error loading trust material", x);
+                               }
+                       }
+
+                       SSLContextBuilder contextBuilder = SSLContexts.custom();
+                       try {
+                               if (keyStore != null) {
+                 contextBuilder.loadKeyMaterial(
+                                                                                                               keyStore,
+                                                                                                               this.ssl.keyStorePasswd.toCharArray()/*,
+                                                                                                               (aliases, socket) -> { 
+                                                                                                                               
+                                                                                                                                       return this.ssl.keyAlias;
+                                                                                                               }*/);
+                               }
+
+                               if (trustStore != null) {                               
+               contextBuilder.loadTrustMaterial(
+                                                                                                               trustStore,
+                                                                                                               (x509Certificates, s) -> false);
+                               }
+
+                               sslContext = contextBuilder.build();
+                       }
+                       catch (Exception x) {
+                               throw new IllegalStateException(
+                                                                               "Error building ssl context", x);
+                       }
+               }
+//!!TODO: teh default hostname verifier needs to be changed!!
+    
+    SSLConnectionSocketFactory sslSocketFactory = null;
+               if (sslContext != null) {
+                       sslSocketFactory =
+                                                       new SSLConnectionSocketFactory(
+                                                       sslContext,
+                                       new String[] { "TLSv1.2" },
+                                       null,
+                                       SSLConnectionSocketFactory.getDefaultHostnameVerifier());
+                               log.info(EELFLoggerDelegate.debugLogger, "SSL connection factory configured");
+               }
+
+               RegistryBuilder<ConnectionSocketFactory> registryBuilder = 
+                                               RegistryBuilder.<ConnectionSocketFactory>create();
+               registryBuilder.register("http", PlainConnectionSocketFactory.getSocketFactory());
+               if (sslSocketFactory != null) {
+                       registryBuilder.register("https", sslSocketFactory);
+               }
+               Registry<ConnectionSocketFactory> registry = registryBuilder.build();
+
+               /*
+               PoolingHttpClientConnectionManager connectionManager = 
+                       new PoolingHttpClientConnectionManager(registry);
+               connectionManager.setMaxTotal(this.poolSize);
+               connectionManager.setDefaultMaxPerRoute(this.poolSize);
+               */
+
+               CredentialsProvider credsProvider = null;
+    if (this.username != null && this.passwd != null) {
+                       credsProvider = new BasicCredentialsProvider();
+                       credsProvider.setCredentials(
+                               AuthScope.ANY, new UsernamePasswordCredentials(
+                                                                                                                                               this.username, this.passwd));
+                       log.info(EELFLoggerDelegate.debugLogger, "Credentials configured");
+               }
+               else {
+                       log.info(EELFLoggerDelegate.debugLogger, "No credentials were provided");
+               }
+
+               HttpClientBuilder clientBuilder = HttpClients.custom();
+
+               //clientBuilder.setConnectionManager(connectionManager);
+               clientBuilder.setConnectionManager(new BasicHttpClientConnectionManager(registry));
+
+               if (sslSocketFactory != null)
+       clientBuilder.setSSLSocketFactory(sslSocketFactory);
+
+               if (credsProvider != null)
+                       clientBuilder.setDefaultCredentialsProvider(credsProvider);
+
+               return clientBuilder.build();
+  }    
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/JSONTags.java b/gateway/src/main/java/org/acumos/federation/gateway/common/JSONTags.java
new file mode 100644 (file)
index 0000000..24a09c4
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+public class JSONTags {
+       
+       public static final String TAG_STATUS_SUCCESS = "success";
+       public static final String TAG_RESPONSE_STATUS = "status";
+       public static final String TAG_REQUEST_FROM = "request_from";
+       public static final String TAG_REQUEST_ID = "request_id";
+       public static final String TAG_REQUEST_BODY = "request_body";
+       public static final String TAG_STATUS_FAILURE = "failure";
+
+       public static final String TAG_RESPONSE_DETAIL = "response_detail";
+       public static final String TAG_RESPONSE_BODY = "response_body";
+       public static final String TAG_RESPONSE_MESSAGE = "request";
+       public static final String TAG_RESPONSE_CODE = "response_code";
+       public static final String TAG_ERROR_CODE_SUCCESS = "200";
+       public static final String TAG_ERROR_CODE_FAILURE = "403";
+       public static final String TAG_ERROR_CODE_EXCEPTION = "500";
+       
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/JsonRequest.java b/gateway/src/main/java/org/acumos/federation/gateway/common/JsonRequest.java
new file mode 100644 (file)
index 0000000..0c318b1
--- /dev/null
@@ -0,0 +1,80 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+* This class represents a common format set for the request body sent from the client.
+* Getters and setters encapsulate the fields of a class by making them accessible 
+* only through its public methods and keep the values themselves private.
+*/
+
+public class JsonRequest<T> implements Serializable{
+
+       private static final long serialVersionUID = 7576436006913504503L;
+
+       /**
+        * Json property requestFrom.
+        */
+       @JsonProperty(value = JSONTags.TAG_REQUEST_FROM)
+       private String requestFrom;
+
+       /**
+        * Json property requestId.
+        */
+       @JsonProperty(value = JSONTags.TAG_REQUEST_ID)
+       private String requestId;
+       
+       /**
+        * Json property body. It represents the type of generic object.
+        */
+       @JsonProperty(value = JSONTags.TAG_REQUEST_BODY)
+       private T body;
+
+       public String getRequestId() {
+               return requestId;
+       }
+
+       public void setRequestId(String requestId) {
+               this.requestId = requestId;
+       }
+       
+       
+       public T getBody() {
+               return body;
+       }
+
+       public void setBody(T body) {
+               this.body = body;
+       }
+
+       public String getRequestFrom() {
+               return requestFrom;
+       }
+
+       public void setRequestFrom(String requestFrom) {
+               this.requestFrom = requestFrom;
+       }
+       
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/common/JsonResponse.java b/gateway/src/main/java/org/acumos/federation/gateway/common/JsonResponse.java
new file mode 100644 (file)
index 0000000..1adbc51
--- /dev/null
@@ -0,0 +1,94 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.common;
+
+
+/**
+* This class represents a common format set for the response send to the client.
+* Getters and setters encapsulate the fields of a class by making them accessible 
+* only through its public methods and keep the values themselves private.
+* @JsonProperty(name), tells Jackson ObjectMapper to map the JSON property name to the annotated Java field's name.
+*/
+
+import java.io.Serializable;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class JsonResponse<T> implements Serializable {
+
+       private static final long serialVersionUID = -2934104266393591755L;
+
+       /**
+        * Json property status.
+        */
+       @JsonProperty(value = JSONTags.TAG_RESPONSE_STATUS)
+       private Boolean status;
+
+       /**
+        * Json property responseDetail.
+        */
+       @JsonProperty(value = JSONTags.TAG_RESPONSE_DETAIL)
+       private String responseDetail;
+
+       /**
+        * Json property responseCode.
+        */
+       @JsonProperty(value = JSONTags.TAG_RESPONSE_CODE)
+       private String responseCode;
+
+       /**
+        * Json property responseBody. It represents the type of generic object.
+        */
+       @JsonProperty(value = JSONTags.TAG_RESPONSE_BODY)
+       private T responseBody;
+       
+       public Boolean getStatus() {
+               return status;
+       }
+
+       public void setStatus(Boolean status) {
+               this.status = status;
+       }
+
+       public String getResponseDetail() {
+               return responseDetail;
+       }
+
+       public void setResponseDetail(String responseDetail) {
+               this.responseDetail = responseDetail;
+       }
+
+       public String getResponseCode() {
+               return responseCode;
+       }
+
+       public void setResponseCode(String responseCode) {
+               this.responseCode = responseCode;
+       }
+
+       public T getResponseBody() {
+               return responseBody;
+       }
+
+       public void setResponseBody(T responseBody) {
+               this.responseBody = responseBody;
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/APIConstants.java b/gateway/src/main/java/org/acumos/federation/gateway/config/APIConstants.java
new file mode 100644 (file)
index 0000000..844d938
--- /dev/null
@@ -0,0 +1,30 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
+
+public class APIConstants {
+
+    public static final String SOLUTIONS = "solutions";
+    public static final String REVISIONS = "revisions";
+    public static final String ARTIFACTS = "artifacts";
+    public static final String DOWNLOAD= "download";
+
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/APINames.java b/gateway/src/main/java/org/acumos/federation/gateway/config/APINames.java
new file mode 100644 (file)
index 0000000..f4bec84
--- /dev/null
@@ -0,0 +1,41 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
+
+/**
+ * 
+ *
+ */
+public class APINames {
+        //Solutions APIs for MarketPlace Catalog
+    public static final String PEER_SOLUTIONS = "/solutions";
+    public static final String PEER_SOLUTIONS_DETAILS = "/solutions/{solutionId}";
+    
+    public static final String PEER_SOLUTIONS_REVISIONS = "/solutions/{solutionId}/revisions";
+    public static final String PEER_SOLUTIONS_REVISIONS_ARTIFACTS = "/solutions/{solutionId}/revisions/{revisionId}";
+    
+    public static final String PEER_ARTIFACT = "/artifacts";
+    public static final String PEER_ARTIFACT_DETAILS = "/artifacts/{artifactId}";
+    public static final String PEER_ARTIFACT_download = "/artifacts/{artifactId}/download";
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/EELFLoggerDelegate.java b/gateway/src/main/java/org/acumos/federation/gateway/config/EELFLoggerDelegate.java
new file mode 100644 (file)
index 0000000..917ca5d
--- /dev/null
@@ -0,0 +1,390 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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=========================================================
+ */
+
+/*-
+ * ================================================================================
+ * ECOMP Portal SDK
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property
+ * ================================================================================
+ * 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.
+ * ================================================================================
+ */
+package org.acumos.federation.gateway.config;
+
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_FQDN;
+import static com.att.eelf.configuration.Configuration.MDC_SERVER_IP_ADDRESS;
+import static com.att.eelf.configuration.Configuration.MDC_SERVICE_INSTANCE_ID;
+
+import java.net.InetAddress;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import org.slf4j.MDC;
+
+import com.att.eelf.configuration.EELFLogger;
+import com.att.eelf.configuration.EELFManager;
+import com.att.eelf.configuration.SLF4jWrapper;
+
+/**
+ * Extends the EELF logger so the output includes the CLASS NAME, which the base
+ * implementation does not provide by default. Example usage:
+ * 
+ * <pre>
+ * private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(MyClass.class);
+ * ..
+ * void methodName() {
+ *   try {
+ *     String result = doWork();
+ *     logger.debug(EELFLoggerDelegate.debugLogger, "methodName: result is {} ", result);
+ *   }
+ *   catch (Exception ex) {
+ *     logger.error(EELFLoggerDelegate.errorLogger, "methodName failed", ex);
+ *   }
+ * }
+ * </pre>
+ *
+ */
+public class EELFLoggerDelegate extends SLF4jWrapper implements EELFLogger {
+
+       public static EELFLogger errorLogger = EELFManager.getInstance().getErrorLogger();
+       public static EELFLogger applicationLogger = EELFManager.getInstance().getApplicationLogger();
+       public static EELFLogger debugLogger = EELFManager.getInstance().getDebugLogger();
+       // Usage of the audit and metrics loggers is required in certain environments
+       public static EELFLogger auditLogger = EELFManager.getInstance().getAuditLogger();
+       public static EELFLogger metricsLogger = EELFManager.getInstance().getMetricsLogger();
+
+       private static final String MDC_CLASS_NAME = "ClassName";
+       private String className;
+       private static ConcurrentMap<String, EELFLoggerDelegate> classMap = new ConcurrentHashMap<String, EELFLoggerDelegate>();
+
+       public EELFLoggerDelegate(String _className) {
+               super(_className);
+               className = _className;
+       }
+
+       /**
+        * Convenience method that gets a logger for the specified class.
+        * 
+        * @see #getLogger(String)
+        * 
+        * @param clazz
+        *            class
+        * @return Instance of EELFLoggerDelegate
+        */
+       public static EELFLoggerDelegate getLogger(Class<?> clazz) {
+               return getLogger(clazz.getName());
+       }
+
+       /**
+        * Gets a logger for the specified class name. If the logger does not
+        * already exist in the map, this creates a new logger.
+        * 
+        * @param className
+        *            If null or empty, uses EELFLoggerDelegate as the class name.
+        * @return Instance of EELFLoggerDelegate
+        */
+       public static EELFLoggerDelegate getLogger(String className) {
+               if (className == null || className == "")
+                       className = EELFLoggerDelegate.class.getName();
+               EELFLoggerDelegate delegate = classMap.get(className);
+               if (delegate == null) {
+                       delegate = new EELFLoggerDelegate(className);
+                       classMap.put(className, delegate);
+               }
+               return delegate;
+       }
+
+       /**
+        * Logs a message at the lowest level: trace.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        */
+       public void trace(EELFLogger logger, String msg) {
+               if (logger.isTraceEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.trace(msg);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message with parameters at the lowest level: trace.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param arguments
+        *            arguments to interpolate into message
+        */
+       public void trace(EELFLogger logger, String msg, Object... arguments) {
+               if (logger.isTraceEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.trace(msg, arguments);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message and throwable at the lowest level: trace.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param th
+        *            throwable to show as a stack trace
+        */
+       public void trace(EELFLogger logger, String msg, Throwable th) {
+               if (logger.isTraceEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.trace(msg, th);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message at the second-lowest level: debug.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        */
+       public void debug(EELFLogger logger, String msg) {
+               if (logger.isDebugEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.debug(msg);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message with parameters at the second-lowest level: debug.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param arguments
+        *            arguments to interpolate into message
+        */
+       public void debug(EELFLogger logger, String msg, Object... arguments) {
+               if (logger.isDebugEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.debug(msg, arguments);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message and throwable at the second-lowest level: debug.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param th
+        *            throwable to show as a stack trace
+        */
+       public void debug(EELFLogger logger, String msg, Throwable th) {
+               if (logger.isDebugEnabled()) {
+                       MDC.put(MDC_CLASS_NAME, className);
+                       logger.debug(msg, th);
+                       MDC.remove(MDC_CLASS_NAME);
+               }
+       }
+
+       /**
+        * Logs a message at info level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        */
+       public void info(EELFLogger logger, String msg) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.info(msg);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message with parameters at info level.
+        *
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param arguments
+        *            arguments to interpolate into message
+        */
+       public void info(EELFLogger logger, String msg, Object... arguments) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.info(msg, arguments);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message and throwable at info level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param th
+        *            throwable to show as a stack trace
+        */
+       public void info(EELFLogger logger, String msg, Throwable th) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.info(msg, th);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message at warn level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        */
+       public void warn(EELFLogger logger, String msg) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.warn(msg);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message with parameters at warn level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param arguments
+        *            arguments to interpolate into message
+        */
+       public void warn(EELFLogger logger, String msg, Object... arguments) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.warn(msg, arguments);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message and throwable at warn level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param th
+        *            throwable to show as a stack trace
+        */
+       public void warn(EELFLogger logger, String msg, Throwable th) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.warn(msg, th);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message at error level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        */
+       public void error(EELFLogger logger, String msg) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.error(msg);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message with parameters at error level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param arguments
+        *            arguments to interpolate into message
+        */
+       public void error(EELFLogger logger, String msg, Object... arguments) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.warn(msg, arguments);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Logs a message and throwable at error level.
+        * 
+        * @param logger
+        *            Logger to use
+        * @param msg
+        *            message to log
+        * @param th
+        *            throwable to show as a stack trace
+        */
+       public void error(EELFLogger logger, String msg, Throwable th) {
+               MDC.put(MDC_CLASS_NAME, className);
+               logger.warn(msg, th);
+               MDC.remove(MDC_CLASS_NAME);
+       }
+
+       /**
+        * Initializes the logger context.
+        */
+       public void init() {
+               setGlobalLoggingContext();
+               final String msg = "############################ Logging is started. ############################";
+               info(applicationLogger, msg);
+               error(errorLogger, msg);
+               debug(debugLogger, msg);
+       }
+
+       /**
+        * Loads all the default logging fields into the MDC context.
+        */
+       private void setGlobalLoggingContext() {
+               MDC.put(MDC_SERVICE_INSTANCE_ID, "");
+               try {
+                       MDC.put(MDC_SERVER_FQDN, InetAddress.getLocalHost().getHostName());
+                       MDC.put(MDC_SERVER_IP_ADDRESS, InetAddress.getLocalHost().getHostAddress());
+               } catch (Exception e) {
+               }
+       }
+
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/SwaggerConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/config/SwaggerConfiguration.java
new file mode 100644 (file)
index 0000000..2a86ab8
--- /dev/null
@@ -0,0 +1,62 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
+
+import org.acumos.federation.gateway.Application;
+import org.acumos.federation.gateway.controller.AbstractController;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * http://www.baeldung.com/swagger-2-documentation-for-spring-rest-api
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfiguration {
+       @Bean
+       public Docket api() {
+               return new Docket(DocumentationType.SWAGGER_2).select() //
+                               .apis(RequestHandlerSelectors.basePackage(AbstractController.class.getPackage().getName())) //
+                               .paths(PathSelectors.any()) //
+                               .build() //
+                               .apiInfo(apiInfo());
+       }
+
+       private ApiInfo apiInfo() {
+               final String version = Application.class.getPackage().getImplementationVersion();
+               ApiInfo apiInfo = new ApiInfo("Acumos Federated Gateway REST API", // title
+                               "Methods provide interfaces to support Federated Model for Acumos.", // description
+                               version == null ? "version not available" : version, // version
+                               "Terms of service", // TOS
+                               new Contact("Federated Acumos - E5 Team", "http://acumos.org", "acumosdev@acumos.org"), // Contact
+                               "License of API", // License
+                               "API license URL"); // License URL
+               return apiInfo;
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/package-info.java b/gateway/src/main/java/org/acumos/federation/gateway/config/package-info.java
new file mode 100644 (file)
index 0000000..8a724a4
--- /dev/null
@@ -0,0 +1,28 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.config;
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/controller/AbstractController.java b/gateway/src/main/java/org/acumos/federation/gateway/controller/AbstractController.java
new file mode 100644 (file)
index 0000000..52998b9
--- /dev/null
@@ -0,0 +1,40 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.controller;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+
+/**
+ * 
+ *
+ */
+public abstract class AbstractController {
+
+       protected static final String APPLICATION_JSON = "application/json";
+
+       protected final ObjectMapper mapper;
+
+       public AbstractController() {
+               mapper = new ObjectMapper();
+       }
+
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/controller/FederatedCatalogController.java b/gateway/src/main/java/org/acumos/federation/gateway/controller/FederatedCatalogController.java
new file mode 100644 (file)
index 0000000..f648c1d
--- /dev/null
@@ -0,0 +1,248 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.controller;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.util.UriComponentsBuilder;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.federation.gateway.common.JSONTags;
+import org.acumos.federation.gateway.common.JsonResponse;
+import org.acumos.federation.gateway.config.APINames;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.service.FederatedCatalogService;
+
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * 
+ *
+ */
+@Controller
+@RequestMapping("/")
+public class FederatedCatalogController extends AbstractController {
+       
+       private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(FederatedCatalogController.class);
+       
+       @Autowired
+       FederatedCatalogService federationGatewayService;
+       
+       
+//     /**
+//      * @param request
+//      *            HttpServletRequest
+//      * @param response
+//      *                      HttpServletResponse
+//      * @return List of Published ML Solutions in JSON format.
+//      */
+//     @CrossOrigin
+//     @ApiOperation(value = "Invoked by Peer Acumos to get a Paginated list of Published Solutions from the Catalog of the local Acumos Instance .", response = MLPSolution.class, responseContainer = "Page")
+//     @RequestMapping(value = {APINames.PEER_SOLUTIONS}, method = RequestMethod.GET, produces = APPLICATION_JSON)
+//     @ResponseBody
+//     public JsonResponse<RestPageResponse<MLPSolution>> getSolutionsListFromPeer(HttpServletRequest request, HttpServletResponse response,
+//                     @RequestParam("pageNumber") Integer pageNumber, @RequestParam("maxSize") Integer maxSize, 
+//                     @RequestParam(required = false) String sortingOrder, @RequestParam(required = false) String mlpModelTypes) {
+//             JsonResponse<RestPageResponse<MLPSolution>> data = null;
+//             RestPageResponse<MLPSolution> peerCatalogSolutions = null;
+//             try {
+//                     data = new JsonResponse<RestPageResponse<MLPSolution>>();
+//                     peerCatalogSolutions = federationGatewayService.getPeerCatalogSolutions(pageNumber, maxSize, sortingOrder, null);
+//                     if(peerCatalogSolutions != null) {
+//                             data.setResponseBody(peerCatalogSolutions);
+//                             logger.debug(EELFLoggerDelegate.debugLogger, "getSolutionsListFromPeer: size is {} ");
+//                     }
+//             } catch (Exception e) {
+//                     logger.error(EELFLoggerDelegate.errorLogger, "Exception Occurred Fetching Solutions for Market Place Catalog", e);
+//             }
+//             return data;
+//     }
+       
+       /**
+        * @param request
+        *            HttpServletRequest
+        * @param response
+        *                      HttpServletResponse
+        * @return List of Published ML Solutions in JSON format.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('PEER')")
+       @ApiOperation(value = "Invoked by Peer Acumos to get a list of Published Solutions from the Catalog of the local Acumos Instance .", response = MLPSolution.class, responseContainer = "List")
+       @RequestMapping(value = {APINames.PEER_SOLUTIONS}, method = RequestMethod.GET, produces = APPLICATION_JSON)
+       @ResponseBody
+       public JsonResponse<List<MLPSolution>> getSolutionsListFromPeer(HttpServletRequest request, HttpServletResponse response, 
+                       @RequestParam(value = "modelTypeCode", required = false) String mlpModelTypes) {
+               JsonResponse<List<MLPSolution>> data = null;
+               List<MLPSolution> peerCatalogSolutions = null;
+               try {
+                       data = new JsonResponse<List<MLPSolution>>();
+                       logger.debug(EELFLoggerDelegate.debugLogger, "getSolutionsListFromPeer: model types " + mlpModelTypes);
+                       peerCatalogSolutions = federationGatewayService.getPeerCatalogSolutionsList(mlpModelTypes);
+                       if(peerCatalogSolutions != null) {
+                               data.setResponseBody(peerCatalogSolutions);
+                               data.setResponseCode(String.valueOf(HttpServletResponse.SC_OK));
+                               data.setResponseDetail(JSONTags.TAG_STATUS_SUCCESS);
+                               data.setStatus(true);
+                               response.setStatus(HttpServletResponse.SC_OK);
+                               logger.debug(EELFLoggerDelegate.debugLogger, "getSolutionsListFromPeer: size is " + peerCatalogSolutions.size());
+                       }
+               } catch (Exception e) {
+                       data.setResponseCode(String.valueOf(HttpServletResponse.SC_BAD_REQUEST));
+                       data.setResponseDetail(JSONTags.TAG_STATUS_FAILURE);
+                       data.setStatus(false);
+                       response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                       logger.error(EELFLoggerDelegate.errorLogger, "Exception Occurred Fetching Solutions for Market Place Catalog", e);
+               }
+               return data;
+       }
+       
+       /**
+        * @param request
+        *            HttpServletRequest
+        * @param response
+        *                      HttpServletResponse
+        * @return List of Published ML Solutions in JSON format.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('PEER')")
+       @ApiOperation(value = "Invoked by Peer Acumos to get a list of Solution Revision from the Catalog of the local Acumos Instance .", response = MLPSolutionRevision.class, responseContainer = "List")
+       @RequestMapping(value = {APINames.PEER_SOLUTIONS_REVISIONS}, method = RequestMethod.GET, produces = APPLICATION_JSON)
+       @ResponseBody
+       public JsonResponse<List<MLPSolutionRevision>> getSolutionsRevisionListFromPeer(HttpServletRequest request, HttpServletResponse response, 
+                       @PathVariable("solutionId") String solutionId) {
+               JsonResponse<List<MLPSolutionRevision>> data = null;
+               List<MLPSolutionRevision> peerCatalogSolutionRevisions= null;
+               try {
+                       data = new JsonResponse<List<MLPSolutionRevision>>();
+                       peerCatalogSolutionRevisions = federationGatewayService.getPeerCatalogSolutionRevision(solutionId);
+                       if(peerCatalogSolutionRevisions != null) {
+                               data.setResponseBody(peerCatalogSolutionRevisions);
+                               data.setResponseCode(String.valueOf(HttpServletResponse.SC_OK));
+                               data.setResponseDetail(JSONTags.TAG_STATUS_SUCCESS);
+                               data.setStatus(true);
+                               response.setStatus(HttpServletResponse.SC_OK);
+                               logger.debug(EELFLoggerDelegate.debugLogger, "getSolutionsRevisionListFromPeer: size is {} ", peerCatalogSolutionRevisions.size());
+                       }
+               } catch (Exception e) {
+                       data.setResponseCode(String.valueOf(HttpServletResponse.SC_BAD_REQUEST));
+                       data.setResponseDetail(JSONTags.TAG_STATUS_FAILURE);
+                       data.setStatus(false);
+                       response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                       logger.error(EELFLoggerDelegate.errorLogger, "Exception Occurred Fetching Solution Revisions for Market Place Catalog", e);
+               }
+               return data;
+       }
+       
+       /**
+        * @param request
+        *            HttpServletRequest
+        * @param response
+        *                      HttpServletResponse
+        * @return List of Published ML Solutions in JSON format.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('PEER')")
+       @ApiOperation(value = "Invoked by Peer Acumos to get a list of Solution Revision Artifacts from the Catalog of the local Acumos Instance .", response = MLPArtifact.class, responseContainer = "List")
+       @RequestMapping(value = {APINames.PEER_SOLUTIONS_REVISIONS_ARTIFACTS}, method = RequestMethod.GET, produces = APPLICATION_JSON)
+       @ResponseBody
+       public JsonResponse<List<MLPArtifact>> getSolutionsRevisionArtifactListFromPeer(HttpServletRequest request, HttpServletResponse response, 
+                       @PathVariable("solutionId") String solutionId, @PathVariable("revisionId") String revisionId) {
+               JsonResponse<List<MLPArtifact>> data = null;
+               List<MLPArtifact> peerSolutionArtifacts= null;
+               try {
+                       data = new JsonResponse<List<MLPArtifact>>();
+                       peerSolutionArtifacts = federationGatewayService.getPeerSolutionArtifacts(solutionId, revisionId);
+                       if(peerSolutionArtifacts != null) {
+                               //re-encode the artifact uri
+                               {
+                     UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(request.getRequestURL().toString());
+
+                                       for (MLPArtifact artifact: peerSolutionArtifacts) {
+                                               artifact.setUri(uriBuilder.replacePath("/artifacts/" + artifact.getArtifactId() + "/download")
+                                                                                                                                                       .toUriString());
+                                       }
+                               }
+
+                               data.setResponseBody(peerSolutionArtifacts);
+                               data.setResponseCode(String.valueOf(HttpServletResponse.SC_OK));
+                               data.setResponseDetail(JSONTags.TAG_STATUS_SUCCESS);
+                               data.setStatus(true);
+                               response.setStatus(HttpServletResponse.SC_OK);
+                               logger.debug(EELFLoggerDelegate.debugLogger, "getSolutionsRevisionArtifactListFromPeer: size is {} ", peerSolutionArtifacts.size());
+                       }
+               } catch (Exception e) {
+                       data.setResponseCode(String.valueOf(HttpServletResponse.SC_BAD_REQUEST));
+                       data.setResponseDetail(JSONTags.TAG_STATUS_FAILURE);
+                       data.setStatus(false);
+                       response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                       logger.error(EELFLoggerDelegate.errorLogger, "Exception Occurred Fetching Solution Revisions Artifacts for Market Place Catalog", e);
+               }
+               return data;
+       }
+       
+       /**
+        * @param request
+        *            HttpServletRequest
+        * @param response
+        *                      HttpServletResponse
+        * @return Archive file of the Artifact for the Solution.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('PEER')")
+       @ApiOperation(value = "API to download the Machine Learning Artifact of the Machine Learning Solution", response = InputStreamResource.class, code = 200)
+       @RequestMapping(value = {APINames.PEER_ARTIFACT_download}, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+       @ResponseBody
+       public InputStreamResource downloadSolutionArtifact(@PathVariable("artifactId") String artifactId,
+               HttpServletRequest request, HttpServletResponse response) {
+               InputStreamResource inputStreamResource = null;
+               try {
+                       inputStreamResource = federationGatewayService.getPeerSolutionArtifactFile(artifactId);
+                       //TODO : Need to Implement a logic to download a Artifact or Docker Image from Nexus
+                       response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+                       response.setHeader("Pragma", "no-cache");
+                       response.setHeader("Expires", "0");
+                       response.setStatus(HttpServletResponse.SC_OK);
+               } catch (Exception e) {
+                       response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
+                       logger.error(EELFLoggerDelegate.errorLogger, "Exception Occurred downloading a artifact for a Solution in Market Place Catalog", e);
+               }
+               return inputStreamResource;
+       }
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/controller/PeerCommunicationTaskScheduler.java b/gateway/src/main/java/org/acumos/federation/gateway/controller/PeerCommunicationTaskScheduler.java
new file mode 100644 (file)
index 0000000..246d9af
--- /dev/null
@@ -0,0 +1,250 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * 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
+ *  
+ * This file 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.acumos.federation.gateway.controller;
+
+import java.util.Calendar;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledFuture;
+
+import javax.annotation.PreDestroy;
+
+import com.google.common.collect.Table;
+import com.google.common.collect.HashBasedTable;
+
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.service.PeerAcumosConfigService;
+import org.acumos.federation.gateway.service.PeerAcumosSubscriptionService;
+import org.acumos.federation.gateway.task.PeerCommunicationTask;
+import org.acumos.federation.gateway.util.Utils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.BeansException;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.stereotype.Component;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+
+import org.acumos.cds.domain.MLPPeer;
+import org.acumos.cds.domain.MLPPeerSubscription;
+
+/**
+ * 
+ * Task Scheduler for the Federated Gateway of Acumos
+ */
+@Component
+@EnableScheduling
+@Configuration
+public class PeerCommunicationTaskScheduler implements         ApplicationContextAware {
+
+       private final EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(PeerCommunicationTaskScheduler.class);
+
+       @Autowired
+       private Environment env;
+
+       @Autowired
+       private PeerAcumosConfigService peerAcumosConfigService;
+
+       @Autowired
+       private PeerAcumosSubscriptionService peerAcumosSubscriptionService;
+
+       private ApplicationContext                      appCtx;
+
+       private static Table<String, Long, PeerTaskHandler> peersSubsTask = HashBasedTable.create();
+
+       private static final SimpleDateFormat dateFormat = new SimpleDateFormat(
+                       "MM/dd/yyyy HH:mm:ss");
+
+
+       public void setApplicationContext(ApplicationContext theCtx) { //throws BeansException {
+    this.appCtx = theCtx;
+       }
+
+       //what was this for?
+       //@Bean(destroyMethod = "shutdown")
+       //public Executor taskExecutor() {
+       //      return Executors.newScheduledThreadPool(10);//Hardcode for now
+       //}
+
+       @Bean
+       public ThreadPoolTaskScheduler taskScheduler() {
+               String name = env.getProperty("federated.instance.name") + "-" + env.getProperty("federated.instance") + "-taskscheduler";
+               ThreadPoolTaskScheduler threadPoolTaskScheduler = null;
+               try {
+                       threadPoolTaskScheduler = (ThreadPoolTaskScheduler)this.appCtx.getBean(name);
+               }
+               catch (BeansException bix) {
+                       //instantiation should fail the first time because we create teh bean below
+               }
+
+               if (threadPoolTaskScheduler == null) {
+                       logger.debug(EELFLoggerDelegate.debugLogger, "creating task scheduler");
+                       threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
+                       threadPoolTaskScheduler.setPoolSize(20);//Make it configurable later
+                       threadPoolTaskScheduler.setBeanName(name);
+                       threadPoolTaskScheduler.initialize();
+               }
+               return threadPoolTaskScheduler; 
+       }
+
+       @PreDestroy
+       public void cleanUpTasks() {
+               logger.debug(EELFLoggerDelegate.debugLogger, "cleanUpTasks");
+               try {
+                       logger.debug(EELFLoggerDelegate.debugLogger, "cleanUpTasks: " + this.peersSubsTask.size() + " tasks");
+                       taskScheduler().shutdown();
+
+               } catch (Exception e) {
+                       logger.error(EELFLoggerDelegate.errorLogger, "Exception occurred while cleanUpTasks: ", e);
+               }
+       }
+
+       protected boolean same(MLPPeerSubscription theFirstSub, MLPPeerSubscription theSecondSub) {
+               logger.debug(EELFLoggerDelegate.debugLogger, "comparing subs : [" + theFirstSub.getSubId() + "," + theFirstSub.getCreated() + "," + theFirstSub.getModified() + "] vs. [" + theSecondSub.getSubId() + "," + theSecondSub.getCreated() + "," + theSecondSub.getModified() + "]");
+               return theFirstSub.getSubId() == theSecondSub.getSubId() &&
+                                        theFirstSub.getCreated().equals(theSecondSub.getCreated()) &&
+                                        ((theFirstSub.getModified() == null && theSecondSub.getModified() == null) ||
+                                         (theFirstSub.getModified() != null && theSecondSub.getModified() != null && theFirstSub.getModified().equals(theSecondSub.getModified()))
+                                        );
+       }
+
+       @Scheduled(fixedRateString = "${peer.jobchecker.interval:400}000")
+       public void checkPeerJobs() {
+
+               //Get the List of MLP Peers
+               List<MLPPeer> mlpPeers = peerAcumosConfigService.getPeers();
+               if(Utils.isEmptyList(mlpPeers)) {
+                       logger.info(EELFLoggerDelegate.debugLogger, "checkPeer : no peers from " + peerAcumosConfigService);
+                       return;
+               }
+               
+               for(MLPPeer mlpPeer : mlpPeers){
+                       logger.info(EELFLoggerDelegate.debugLogger, "checkPeer : " + mlpPeer);
+
+                       //cancel peer tasks for inactive peers 
+                       if(!mlpPeer.isActive()) {
+                               //cancel all peer sub tasks for this peer
+                               logger.debug(EELFLoggerDelegate.debugLogger, "checkPeer : peer no longer active, removing active tasks");
+                               Map<Long, PeerTaskHandler> subsTask = this.peersSubsTask.row(mlpPeer.getPeerId());
+                               if (subsTask != null) {
+                                       for (Map.Entry<Long, PeerTaskHandler> subTaskEntry: subsTask.entrySet()) {
+                                               subTaskEntry.getValue().stopTask();
+                                               this.peersSubsTask.remove(mlpPeer.getPeerId(), subTaskEntry.getKey());
+                                       }
+                               }
+
+                               //or peers that have been removed
+                               //
+                               continue;
+                       }
+
+                       List<MLPPeerSubscription> mlpSubs = peerAcumosSubscriptionService.getPeerSubscriptions(mlpPeer.getPeerId());
+                       if(Utils.isEmptyList(mlpSubs)) {
+                               //the peer is still there but has no subscriptions: cancel any ongoing tasks
+
+                               continue;
+                       }
+
+                       for(MLPPeerSubscription mlpSub : mlpSubs) {
+                               logger.info(EELFLoggerDelegate.debugLogger, "checkSub " + mlpSub);
+                               PeerTaskHandler peerSubTask = peersSubsTask.get(mlpPeer.getPeerId(), mlpSub.getSubId());
+                               if (peerSubTask != null) {
+                                       //was the subscription updated? if yes, cancel current task. 
+                                       MLPPeerSubscription mlpCurrentSub = peerSubTask.getSubscription();
+                                       if (!same(mlpSub, mlpCurrentSub)) {
+                                               logger.debug(EELFLoggerDelegate.debugLogger, "checkSub: subscription was updated, stopping current task");
+                                               peerSubTask.stopTask();
+                                               peerSubTask = null; //in order to trigger its reset below: no need to remove the entry as we are about
+                                                                                                                               //to replace it with a new one.
+                                       }
+                               }
+
+                               if (peerSubTask == null) {
+                                       logger.info(EELFLoggerDelegate.debugLogger, "Scheduled peer sub task for " + mlpPeer.getApiUrl());
+                                       this.peersSubsTask.put(mlpPeer.getPeerId(), mlpSub.getSubId(), new PeerTaskHandler().startTask(mlpPeer, mlpSub));
+                               }
+                       }
+               }
+       }
+
+       /**
+        * We need this contraption simply because we cannot retrieve the task (in order to check the subscription it is
+        * working on) from the ScheduledFuture ..
+        */
+       private class PeerTaskHandler {
+
+               private ScheduledFuture                         future;
+               private PeerCommunicationTask   task;
+
+               public synchronized PeerTaskHandler startTask(MLPPeer thePeer, MLPPeerSubscription theSub) {
+                       this.task =     (PeerCommunicationTask)PeerCommunicationTaskScheduler.this.appCtx.getBean("peerSubscriptionTask");
+                       this.future = PeerCommunicationTaskScheduler.this.taskScheduler().scheduleAtFixedRate(
+                                                                                                                                                       this.task.handle(thePeer, theSub), theSub.getRefreshInterval());
+                       return this;
+               }
+
+               public synchronized PeerTaskHandler stopTask() {
+                       if (this.future == null)
+                               throw new IllegalStateException("Not started");
+
+                       this.future.cancel(true);
+                       return this;
+               }
+               
+               public synchronized MLPPeerSubscription getSubscription() {
+              &nbs