Merge "Patches to known issues"
authorMukesh Mantan <MM00542237@TechMahindra.com>
Wed, 6 Jun 2018 00:22:29 +0000 (00:22 +0000)
committerGerrit Code Review <gerrit@acumos.org>
Wed, 6 Jun 2018 00:22:29 +0000 (00:22 +0000)
47 files changed:
gateway/application-acumosa.properties
gateway/pom.xml
gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java
gateway/src/main/java/org/acumos/federation/gateway/cds/Artifact.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactType.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/Mapper.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/Solution.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevision.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevisionBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/Updater.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/common/AbstractClient.java
gateway/src/main/java/org/acumos/federation/gateway/common/Clients.java
gateway/src/main/java/org/acumos/federation/gateway/common/FederationClient.java
gateway/src/main/java/org/acumos/federation/gateway/common/JsonResponse.java
gateway/src/main/java/org/acumos/federation/gateway/config/AdapterConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/DockerConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/config/FederationConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/GatewayConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/LocalConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/controller/CatalogController.java
gateway/src/main/java/org/acumos/federation/gateway/controller/ControllerContext.java
gateway/src/main/java/org/acumos/federation/gateway/security/AuthenticationConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/security/Peer.java
gateway/src/main/java/org/acumos/federation/gateway/service/ArtifactService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/CatalogService.java
gateway/src/main/java/org/acumos/federation/gateway/service/PeerService.java
gateway/src/main/java/org/acumos/federation/gateway/service/PeerSubscriptionService.java
gateway/src/main/java/org/acumos/federation/gateway/service/ServiceContext.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/AbstractServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/AbstractServiceLocalImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceLocalImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/CatalogServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/CatalogServiceLocalImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerServiceLocalImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/PeerSubscriptionServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/ServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/task/PeerSubscriptionTask.java
gateway/src/test/java/org/acumos/federation/gateway/test/PeerGatewayTest.java
gateway/src/test/java/org/acumos/federation/gateway/test/TestAdapter.java
gateway/src/test/resources/acumosa-peers.json
gateway/src/test/resources/acumosb-catalog.json
gateway/src/test/resources/acumosb-peers.json
gateway/src/test/resources/test-peers.json

index 108e0df..3448620 100644 (file)
@@ -1,4 +1,3 @@
-#pretend we are an adapter so that we can use local peer config
 federation.instance=adapter
 federation.instance.name=test
 #federation.instance=gateway
index e410270..db5b63b 100644 (file)
@@ -168,6 +168,11 @@ limitations under the License.
                        <artifactId>commons-lang3</artifactId>
                        <version>3.6</version>
                </dependency>
+               <dependency>
+                       <groupId>com.github.docker-java</groupId>
+                       <artifactId>docker-java</artifactId>
+                       <version>3.0.14</version>
+               </dependency>
                <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
index 2c663ad..cf390a4 100644 (file)
@@ -42,8 +42,12 @@ import org.acumos.federation.gateway.common.Clients;
 import org.acumos.federation.gateway.common.FederationClient;
 import org.acumos.federation.gateway.util.Errors;
 import org.acumos.federation.gateway.cds.SubscriptionScope;
+import org.acumos.federation.gateway.cds.Solution;
+import org.acumos.federation.gateway.cds.SolutionRevision;
+import org.acumos.federation.gateway.cds.Artifact;
 
-import org.acumos.nexus.client.data.UploadArtifactInfo;
+import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ServiceException;
 
 import org.springframework.beans.factory.BeanInitializationException;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -69,6 +73,9 @@ public class PeerGateway {
        private Environment env;
        @Autowired
        private Clients clients;
+       @Autowired
+       private ArtifactService artifacts;
+
 
        public PeerGateway() {
                log.trace(EELFLoggerDelegate.debugLogger, "PeerGateway::new");
@@ -183,23 +190,15 @@ public class PeerGateway {
                private MLPSolution createMLPSolution(MLPSolution peerSolution, ICommonDataServiceRestClient cdsClient) {
                        log.info(EELFLoggerDelegate.debugLogger,
                                        "Creating Local MLP Solution for peer solution " + peerSolution);
-                       MLPSolution localSolution = new MLPSolution();
-                       localSolution.setSolutionId(peerSolution.getSolutionId());
-                       localSolution.setName(peerSolution.getName());
-                       localSolution.setDescription(peerSolution.getDescription());
-                       localSolution.setAccessTypeCode(this.sub.getAccessType());
-                       localSolution.setMetadata(peerSolution.getMetadata());
-                       localSolution.setModelTypeCode(peerSolution.getModelTypeCode());
-                       localSolution.setProvider(this.peer.getName());
-                       localSolution.setActive(peerSolution.isActive());
-                       localSolution.setToolkitTypeCode(peerSolution.getToolkitTypeCode());
-                       localSolution.setValidationStatusCode(this.peer.getValidationStatusCode());
+
+                       Solution localSolution = Solution.buildFrom(peerSolution)
+                                                                                                                                       .withAccessTypeCode(this.sub.getAccessType())
+                                                                                                                                       .withValidationStatusCode(this.peer.getValidationStatusCode())
+                                                                                                                                       .withProvider(this.peer.getName())
                        //should the creted/modified reflect this information or the information we got from the peer ?
-                       localSolution.setCreated(peerSolution.getCreated());
-                       localSolution.setModified(peerSolution.getModified());
-                       localSolution.setOwnerId(getOwnerId(this.sub));
-                       localSolution.setSourceId(this.peer.getPeerId());
-                       localSolution.setOrigin(peerSolution.getOrigin());
+                                                                                                                                       .withOwner(getOwnerId(this.sub))
+                                                                                                                                       .withSource(this.peer.getPeerId())
+                                                                                                                                       .build();
                        try {
                                cdsClient.createSolution(localSolution);
                                return localSolution;
@@ -215,21 +214,16 @@ public class PeerGateway {
                        }
                }
 
-               private MLPSolutionRevision createMLPSolutionRevision(MLPSolutionRevision peerSolutionRevision,
+               private MLPSolutionRevision createMLPSolutionRevision(MLPSolutionRevision peerRevision,
                                ICommonDataServiceRestClient cdsClient) {
-                       MLPSolutionRevision localSolutionRevision = new MLPSolutionRevision();
-                       localSolutionRevision.setSolutionId(peerSolutionRevision.getSolutionId());
-                       localSolutionRevision.setRevisionId(peerSolutionRevision.getRevisionId());
-                       localSolutionRevision.setVersion(peerSolutionRevision.getVersion());
-                       localSolutionRevision.setDescription(peerSolutionRevision.getDescription());
-                       localSolutionRevision.setOwnerId(getOwnerId(this.sub));
-                       localSolutionRevision.setMetadata(peerSolutionRevision.getMetadata());
-                       localSolutionRevision.setCreated(peerSolutionRevision.getCreated());
-                       localSolutionRevision.setModified(peerSolutionRevision.getModified());
-                       localSolutionRevision.setSourceId(this.peer.getPeerId());
+
+                       SolutionRevision localRevision = SolutionRevision.buildFrom(peerRevision)
+                                                                                                                                                                       .withOwner(getOwnerId(this.sub))
+                                                                                                                                                                       .withSource(this.peer.getPeerId())
+                                                                                                                                                                       .build();
                        try {
-                               cdsClient.createSolutionRevision(localSolutionRevision);
-                               return localSolutionRevision;
+                               cdsClient.createSolutionRevision(localRevision);
+                               return localRevision;
                        }
                        catch (HttpStatusCodeException restx) {
                                log.error(EELFLoggerDelegate.errorLogger,
@@ -243,24 +237,15 @@ public class PeerGateway {
                        }
                }
 
-               private MLPArtifact createMLPArtifact(String theSolutionId, String theRevisionId, MLPArtifact mlpArtifact,
+               private MLPArtifact createMLPArtifact(String theSolutionId, String theRevisionId, MLPArtifact peerArtifact,
                                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(getOwnerId(this.sub));
-                       artifact.setSize(mlpArtifact.getSize());
-                       ;
-                       artifact.setUri(mlpArtifact.getUri());
-                       artifact.setVersion(mlpArtifact.getVersion());
+
+                       Artifact artifact = Artifact.buildFrom(peerArtifact)
+                                                                                                               .withOwner(getOwnerId(this.sub))
+                                                                                                               .build();
                        try {
                                cdsClient.createArtifact(artifact);
-                               cdsClient.addSolutionRevisionArtifact(theSolutionId, theRevisionId, mlpArtifact.getArtifactId());
+                               cdsClient.addSolutionRevisionArtifact(theSolutionId, theRevisionId, artifact.getArtifactId());
                                return artifact;
                        }
                        catch (HttpStatusCodeException restx) {
@@ -274,23 +259,16 @@ public class PeerGateway {
                        }
                }
 
-               private MLPArtifact copyMLPArtifact(MLPArtifact peerMLPArtifact, MLPArtifact localMLPArtifact) {
-
-                       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(getOwnerId(this.sub));
-                       localMLPArtifact.setSize(peerMLPArtifact.getSize());
-                       localMLPArtifact.setUri(peerMLPArtifact.getUri());
-                       localMLPArtifact.setVersion(peerMLPArtifact.getVersion());
-                       return localMLPArtifact;
+               /* we create a new one as nothing is preserved. assumes matching ids. */
+               private MLPArtifact copyMLPArtifact(MLPArtifact peerArtifact, MLPArtifact localArtifact) {
+
+                       return Artifact.buildFrom(peerArtifact)
+                                                               .withId(localArtifact.getArtifactId())
+                                                               .withOwner(getOwnerId(this.sub))
+                                                               .build();
                }
 
-               private MLPSolution updateMLPSolution(MLPSolution peerSolution, MLPSolution localSolution,
+               private MLPSolution updateMLPSolution(final MLPSolution peerSolution, final MLPSolution localSolution,
                                ICommonDataServiceRestClient cdsClient) {
                        log.info(EELFLoggerDelegate.debugLogger,
                                        "Updating Local MLP Solution for peer solution " + peerSolution);
@@ -298,43 +276,38 @@ public class PeerGateway {
                        if (!peerSolution.getSolutionId().equals(localSolution.getSolutionId()))
                                throw new IllegalArgumentException("Local and Peer identifier mismatch");
 
-                       //localSolution.setSolutionId(peerSolution.getSolutionId());
-                       localSolution.setName(peerSolution.getName());
-                       localSolution.setDescription(peerSolution.getDescription());
-                       localSolution.setAccessTypeCode(peerSolution.getAccessTypeCode());
-                       localSolution.setMetadata(peerSolution.getMetadata());
-                       localSolution.setModelTypeCode(peerSolution.getModelTypeCode());
-                       localSolution.setProvider(peerSolution.getProvider());
-                       localSolution.setActive(peerSolution.isActive());
-                       localSolution.setToolkitTypeCode(peerSolution.getToolkitTypeCode());
-                       // reset validation status to its default
-                       localSolution.setValidationStatusCode(this.peer.getValidationStatusCode());
-                       {
-                               String newOwnerId = getOwnerId(this.sub);
-                               if (!newOwnerId.equals(localSolution.getOwnerId())) {
-                                       // is this solution being updated as part of different/new subscription?
-                                       log.warn(EELFLoggerDelegate.errorLogger, "updating solution " + localSolution.getSolutionId()
-                                                       + " as part of subscription " + this.sub.getSubId() + " triggers an ownership change");
-                               }
-                               localSolution.setOwnerId(newOwnerId);
-                       }
-
-                       {
-                               if (localSolution.getSourceId() == null) {
-                                       //this is a local solution that made its way back
-                                       log.info(EELFLoggerDelegate.debugLogger, "Solution " + localSolution.getSolutionId()
-                                                       + " as part of subscription " + this.sub.getSubId() + " was originally provisioned locally");
-                               }
-                               else {
-                                       String newSourceId = this.peer.getPeerId();
-                                       if (!newSourceId.equals(localSolution.getSourceId())) {
-                                               // we will see this if a solution is available in more than one peer
-                                               log.warn(EELFLoggerDelegate.errorLogger, "updating solution " + localSolution.getSolutionId()
-                                                               + " as part of subscription " + this.sub.getSubId() + " triggers a source change");
-                                       }
-                                       localSolution.setSourceId(newSourceId);
-                               }
-                       }
+                       //start with the peer solution and pick the few local values we ought to preserve or impose
+                       Solution solution = Solution.buildFrom(peerSolution)
+                                                                                                                       .withAccessTypeCode(localSolution.getAccessTypeCode())
+                                                                                                                       .withValidationStatusCode(this.peer.getValidationStatusCode()) //reset
+                                                                                                                       .withProvider(this.peer.getName())
+                                                                                                                       .withOwner((Object... args) -> {
+                                                                                                                                       String newOwnerId = getOwnerId(this.sub);
+                                                                                                                                               if (!newOwnerId.equals(localSolution.getOwnerId())) {
+                                                                                                                                                       // is this solution being updated as part of different/new subscription?
+                                                                                                                                                       log.warn(EELFLoggerDelegate.errorLogger, "updating solution " +localSolution.getSolutionId()
+                                                                                                                                                       + " as part of subscription " + this.sub.getSubId() + " triggers an ownership change");
+                                                                                                                                               }
+                                                                                                                                               return newOwnerId;
+                                                                                                                               })
+                                                                                                                       .withSource((Object... args) -> {
+                                                                                                                                       if (localSolution.getSourceId() == null) {
+                                                                                                                                               //this is a local solution that made its way back
+                                                                                                                                               log.info(EELFLoggerDelegate.debugLogger, "Solution " + localSolution.getSolutionId()
+                                                                                                                                               + " as part of subscription " + this.sub.getSubId() + " was originally provisioned locally");
+                                                                                                                                               return null;
+                                                                                                                                       }
+                                                                                                                                       else {
+                                                                                                                                               String newSourceId = this.peer.getPeerId();
+                                                                                                                                               if (!newSourceId.equals(localSolution.getSourceId())) {
+                                                                                                                                                       // we will see this if a solution is available in more than one peer
+                                                                                                                                                       log.warn(EELFLoggerDelegate.errorLogger, "updating solution " +localSolution.getSolutionId()
+                                                                                                                                                       + " as part of subscription " + this.sub.getSubId() + " triggers a source change");
+                                                                                                                                               }
+                                                                                                                                               return newSourceId;
+                                                                                                                                       }
+                                                                                                                               })
+                                                                                                                       .build();
 
                        try {
                                cdsClient.updateSolution(localSolution);
@@ -466,7 +439,7 @@ public class PeerGateway {
                                        else {
                                                if (!peerArtifact.getVersion().equals(localArtifact.getVersion())) {
                                                        // update local artifact
-                                                       copyMLPArtifact(peerArtifact, localArtifact);
+                                                       localArtifact = copyMLPArtifact(peerArtifact, localArtifact);
                                                        doUpdate = true;
                                                }
                                        }
@@ -487,28 +460,14 @@ public class PeerGateway {
                                                        log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve acumos artifact content", x);
                                                }
 
-                                               UploadArtifactInfo uploadInfo = null;
-                                               if (artifactContent != null) {
-                                                       try {
-                                                               uploadInfo = PeerGateway.this.clients.getNexusClient()
-                                                                               .uploadArtifact(PeerGateway.this.env.getProperty("nexus.groupId"),
-                                                                                               localArtifact.getName(), /* probably wrong */
-                                                                                               localArtifact.getVersion(), "", /* should receive this from peer */
-                                                                                               artifactContent.contentLength(), artifactContent.getInputStream());
-                                                               log.info(EELFLoggerDelegate.debugLogger, "Wrote artifact content locally to {}", uploadInfo.getArtifactMvnPath()); 
-                                                       }
-                                                       catch (Exception x) {
-                                                               log.error(EELFLoggerDelegate.errorLogger,
-                                                                               "Failed to push artifact content to local Nexus repo", x);
-                                                       }
-                                               }
-
-                                               if (uploadInfo != null) {
-                                                       // update artifact with local repo reference
-                                                       localArtifact.setUri(uploadInfo.getArtifactMvnPath());
-                                                       // the artifact info will need to be updated with local content uri
+                                               try {
+                                                       artifacts.putArtifactContent(localArtifact, artifactContent);
                                                        doUpdate = true;
                                                }
+                                               catch (ServiceException sx) {
+                                                       log.error(EELFLoggerDelegate.errorLogger,
+                                                                               "Failed to store artifact content to local repo", sx);
+                                               }
                                        }
 
                                        if (doUpdate) {
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/Artifact.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/Artifact.java
new file mode 100644 (file)
index 0000000..4edd0e8
--- /dev/null
@@ -0,0 +1,49 @@
+/*-
+ * ===============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.cds;
+
+import org.acumos.cds.domain.MLPArtifact;
+
+/**
+ */
+public class Artifact extends MLPArtifact {
+
+       public Artifact() {
+       }
+
+       public Artifact(MLPArtifact theCDSArtifact) {
+               super(theCDSArtifact);
+       }
+       
+       public Artifact(Artifact theArtifact) {
+               super(theArtifact);
+       }
+
+       public static ArtifactBuilder build() {
+               return new ArtifactBuilder(new Artifact());
+       }
+
+       public static ArtifactBuilder buildFrom(MLPArtifact theArtifact) {
+               return new ArtifactBuilder(new Artifact(theArtifact));
+       }
+
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactBuilder.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactBuilder.java
new file mode 100644 (file)
index 0000000..fa874da
--- /dev/null
@@ -0,0 +1,96 @@
+/*-
+ * ===============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.cds;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ */
+public class ArtifactBuilder {
+
+       private Artifact artifact;
+
+       protected ArtifactBuilder(Artifact theArtifact) {
+               this.artifact = theArtifact;
+       }
+
+       public Artifact build() {
+               return this.artifact;
+       } 
+
+       public ArtifactBuilder withCreatedDate(Date theDate) {
+               this.artifact.setCreated(theDate);
+               return this;
+       }
+
+       public ArtifactBuilder withModifiedDate(Date theDate) {
+               this.artifact.setModified(theDate);
+               return this;
+       }
+
+       public ArtifactBuilder withId(String theArtifactId) {
+               this.artifact.setArtifactId(theArtifactId);
+               return this;
+       }
+
+       public ArtifactBuilder withOwner(String theOwnerId) {
+               this.artifact.setOwnerId(theOwnerId);
+               return this;
+       }
+
+       public ArtifactBuilder withVersion(String theVersion) {
+               this.artifact.setVersion(theVersion);
+               return this;
+       }
+
+       public ArtifactBuilder withTypeCode(String theTypeCode) {
+               this.artifact.setArtifactTypeCode(theTypeCode);
+               return this;
+       }
+
+       public ArtifactBuilder withName(String theName) {
+               this.artifact.setName(theName);
+               return this;
+       }
+
+       public ArtifactBuilder withDescription(String theDesc) {
+               this.artifact.setDescription(theDesc);
+               return this;
+       }
+
+       public ArtifactBuilder withMetadata(String theMetadata) {
+               this.artifact.setMetadata(theMetadata);
+               return this;
+       }
+
+       public ArtifactBuilder withUri(String theUri) {
+               this.artifact.setUri(theUri);
+               return this;
+       }
+       
+       public ArtifactBuilder withSize(Integer theSize) {
+               this.artifact.setSize(theSize);
+               return this;
+       }
+
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactType.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/ArtifactType.java
new file mode 100644 (file)
index 0000000..a4ba406
--- /dev/null
@@ -0,0 +1,67 @@
+/*-
+ * ===============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.cds;
+
+import java.util.EnumSet;
+import org.acumos.cds.domain.MLPArtifactType;
+import org.acumos.cds.ArtifactTypeCode;
+
+/**
+ * Supplements the CDS representation of artifact type information.
+ */
+public enum ArtifactType {
+
+
+  Blueprint(ArtifactTypeCode.BP.name()), //
+  Cdump(ArtifactTypeCode.CD.name()), //
+  DockerImage(ArtifactTypeCode.DI.name()), //
+  DataSource(ArtifactTypeCode.DS.name()), //
+  Metadata(ArtifactTypeCode.MD.name()), //
+  ModelH2O(ArtifactTypeCode.MH.name()), //
+  ModelImage(ArtifactTypeCode.MI.name()), //
+  ModelR(ArtifactTypeCode.MR.name()), //
+  ModelScikit(ArtifactTypeCode.MS.name()), //
+  ModelTensorflow(ArtifactTypeCode.MT.name()), //
+  ToscaTemplate(ArtifactTypeCode.TE.name()), //
+  ToscaGenerator(ArtifactTypeCode.TG.name()), //
+  ToscaSchema(ArtifactTypeCode.TS.name()), //
+  ToscaTranslate(ArtifactTypeCode.TT.name()), //
+  ProtobufFile(ArtifactTypeCode.PJ.name());
+
+       private String                          code;
+
+       private ArtifactType(String theCode) {
+               this.code = theCode;
+       }
+
+       public String code() {
+               return this.code;
+       }
+
+       public static ArtifactType forCode(final String theCode) {
+               return EnumSet.allOf(ArtifactType.class)
+                                               .stream()
+                                               .filter(status -> status.code().equals(theCode))
+                                               .findFirst()
+                                               .orElse(null);
+       }
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/Mapper.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/Mapper.java
new file mode 100644 (file)
index 0000000..e5d1712
--- /dev/null
@@ -0,0 +1,104 @@
+/*-
+ * ===============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.cds;
+
+import java.io.IOException;
+
+import com.fasterxml.jackson.core.Version;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.Module;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.cds.domain.MLPArtifact;
+
+/**
+ * Provides a Jackson ObjectMapper configured with an extension module for processing
+ * federation data where CDS data is declared.
+ */
+public class Mapper {
+
+
+       public static ObjectMapper build() {
+               ObjectMapper mapper = new ObjectMapper();
+
+               SimpleModule fedModule =
+      new SimpleModule("CDSModule",
+          new Version(1, 0, 0, null));
+    fedModule.addDeserializer(MLPSolution.class, new SolutionDeserializer());
+    fedModule.addDeserializer(MLPSolutionRevision.class, new SolutionRevisionDeserializer());
+    fedModule.addDeserializer(MLPArtifact.class, new ArtifactDeserializer());
+               mapper.registerModule(fedModule);
+
+
+               return mapper;
+       }
+       
+       private static class SolutionDeserializer extends StdDeserializer<MLPSolution> {
+               public SolutionDeserializer() {
+                       super(MLPSolution.class);
+               }
+               @Override
+       public MLPSolution deserialize(JsonParser theParser, DeserializationContext theCtx) 
+                                                                                                                                                                                               throws IOException, JsonProcessingException {
+         ObjectMapper mapper = (ObjectMapper) theParser.getCodec();
+       return mapper.readValue(theParser, Solution.class);
+       }
+       }
+
+       private static class SolutionRevisionDeserializer extends StdDeserializer<MLPSolutionRevision> {
+               public SolutionRevisionDeserializer() {
+                       super(MLPSolutionRevision.class);
+               }
+               @Override
+       public MLPSolutionRevision deserialize(JsonParser theParser, DeserializationContext theCtx) 
+                                                                                                                                                                                                       throws IOException, JsonProcessingException {
+         ObjectMapper mapper = (ObjectMapper) theParser.getCodec();
+       return mapper.readValue(theParser, SolutionRevision.class);
+       }
+       }
+
+       private static class ArtifactDeserializer extends StdDeserializer<MLPArtifact> {
+               public ArtifactDeserializer() {
+                       super(MLPArtifact.class);
+               }
+               @Override
+       public MLPArtifact deserialize(JsonParser theParser, DeserializationContext theCtx) 
+                                                                                                                                                                                               throws IOException, JsonProcessingException {
+         ObjectMapper mapper = (ObjectMapper) theParser.getCodec();
+       return mapper.readValue(theParser, Artifact.class);
+       }
+       }
+
+
+}
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/Solution.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/Solution.java
new file mode 100644 (file)
index 0000000..26b8716
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ===============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.cds;
+
+import java.util.List;
+
+import org.acumos.cds.domain.MLPSolution;
+import org.acumos.cds.domain.MLPSolutionRevision;
+
+/**
+ * Supplements the CDS representation of a solution with related information: revisions.
+ * Allows federation to pack information passed between peers.
+ */
+public class Solution extends MLPSolution {
+
+       private List<MLPSolutionRevision>               revisions;
+
+       public Solution() {
+       }
+
+       public Solution(MLPSolution theCDSSolution) {
+               super(theCDSSolution);
+       }
+
+       public void setRevisions(List<MLPSolutionRevision> theRevisions) {
+               this.revisions = theRevisions;
+       }
+
+       public List<MLPSolutionRevision>        getRevisions() {
+               return this.revisions;
+       }
+       
+       public static SolutionBuilder build() {
+               return new SolutionBuilder(new Solution());
+       }
+
+       public static SolutionBuilder buildFrom(MLPSolution theSolution) {
+               return new SolutionBuilder(new Solution(theSolution));
+       }
+
+       @Override
+       public String toString() {
+               return super.toString() + (this.revisions == null ? "[]" : this.revisions.toString()) ;
+       }
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionBuilder.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionBuilder.java
new file mode 100644 (file)
index 0000000..c87ef59
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * ===============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.cds;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Supplements the CDS representation of a solution with related information: revisions.
+ * Allows federation to pack information passed between peers.
+ */
+public class SolutionBuilder {
+
+       private Solution solution;
+
+       protected SolutionBuilder(Solution theSolution) {
+               this.solution = theSolution;
+       }
+
+       public Solution build() {
+               return this.solution;
+       } 
+
+       public SolutionBuilder withCreatedDate(Date theDate) {
+               this.solution.setCreated(theDate);
+               return this;
+       }
+
+       public SolutionBuilder withModifiedDate(Date theDate) {
+               this.solution.setModified(theDate);
+               return this;
+       }
+
+       public SolutionBuilder withId(String theSolutionId) {
+               this.solution.setSolutionId(theSolutionId);
+               return this;
+       }
+
+       public SolutionBuilder withName(String theName) {
+               this.solution.setName(theName);
+               return this;
+       }
+
+       public SolutionBuilder withMetadata(String theMetadata) {
+               this.solution.setMetadata(theMetadata);
+               return this;
+       }
+
+       public SolutionBuilder withProvider(String theProvider) {
+               this.solution.setProvider(theProvider);
+               return this;
+       }
+
+       public SolutionBuilder withDescription(String theDesc) {
+               this.solution.setDescription(theDesc);
+               return this;
+       }
+
+       public SolutionBuilder withActive(boolean isActive) {
+               this.solution.setActive(isActive);
+               return this;
+       }
+
+       public SolutionBuilder withAccessTypeCode(String theCode) {
+               this.solution.setAccessTypeCode(theCode);
+               return this;
+       }
+
+       public SolutionBuilder withModelTypeCode(String theCode) {
+               this.solution.setModelTypeCode(theCode);
+               return this;
+       }
+
+       public SolutionBuilder withToolkitTypeCode(String theCode) {
+               this.solution.setToolkitTypeCode(theCode);
+               return this;
+       }
+
+       public SolutionBuilder withValidationStatusCode(String theCode) {
+               this.solution.setValidationStatusCode(theCode);
+               return this;
+       }
+
+       public SolutionBuilder withOrigin(String theOrigin) {
+               this.solution.setOrigin(theOrigin);
+               return this;
+       }
+
+       public SolutionBuilder withOwner(String theOwnerId) {
+               this.solution.setOwnerId(theOwnerId);
+               return this;
+       }
+       
+       public SolutionBuilder withOwner(Updater<String, Object> theUpdater, Object... theArgs) {
+               String newOwner = theUpdater.update(theArgs);
+               if (newOwner != null)
+                       this.solution.setOwnerId(newOwner);
+               return this;
+       }
+
+       public SolutionBuilder withSource(String theSourceId) {
+               this.solution.setSourceId(theSourceId);
+               return this;
+       }
+
+       public SolutionBuilder withSource(Updater<String, Object> theUpdater, Object... theArgs) {
+               String newSource = theUpdater.update(theArgs);
+               if (newSource != null)
+                       this.solution.setSourceId(newSource);
+               return this;
+       }
+
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevision.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevision.java
new file mode 100644 (file)
index 0000000..b37c82a
--- /dev/null
@@ -0,0 +1,60 @@
+/*-
+ * ===============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.cds;
+
+import java.util.List;
+
+import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.cds.domain.MLPArtifact;
+
+/**
+ * Supplements the CDS representation of a solution with related information: revisions.
+ * Allows federation to pack information passed between peers.
+ */
+public class SolutionRevision extends MLPSolutionRevision {
+
+       private List<MLPArtifact>               artifacts;
+
+       public SolutionRevision() {
+       }
+
+       public SolutionRevision(MLPSolutionRevision theCDSRevision) {
+               super(theCDSRevision);
+       }
+
+       public void setArtifacts(List<MLPArtifact> theArtifacts) {
+               this.artifacts = theArtifacts;
+       }
+
+       public List<MLPArtifact>        getArtifacts() {
+               return this.artifacts;
+       }
+
+       public static SolutionRevisionBuilder build() {
+               return new SolutionRevisionBuilder(new SolutionRevision());
+       }
+
+       public static SolutionRevisionBuilder buildFrom(MLPSolutionRevision theRevision) {
+               return new SolutionRevisionBuilder(new SolutionRevision(theRevision));
+       }
+
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevisionBuilder.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevisionBuilder.java
new file mode 100644 (file)
index 0000000..241597c
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * ===============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.cds;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ */
+public class SolutionRevisionBuilder {
+
+       private SolutionRevision revision;
+
+       protected SolutionRevisionBuilder(SolutionRevision theRevision) {
+               this.revision = theRevision;
+       }
+
+       public SolutionRevision build() {
+               return this.revision;
+       } 
+
+       public SolutionRevisionBuilder withCreatedDate(Date theDate) {
+               this.revision.setCreated(theDate);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withModifiedDate(Date theDate) {
+               this.revision.setModified(theDate);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withRevisionId(String theRevisionId) {
+               this.revision.setRevisionId(theRevisionId);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withDescription(String theDesc) {
+               this.revision.setDescription(theDesc);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withMetadata(String theMetadata) {
+               this.revision.setMetadata(theMetadata);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withVersion(String theVersion) {
+               this.revision.setVersion(theVersion);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withOrigin(String theOrigin) {
+               this.revision.setOrigin(theOrigin);
+               return this;
+       }
+
+       public SolutionRevisionBuilder withOwner(String theOwnerId) {
+               this.revision.setOwnerId(theOwnerId);
+               return this;
+       }
+       
+       public SolutionRevisionBuilder withSource(String theSourceId) {
+               this.revision.setSourceId(theSourceId);
+               return this;
+       }
+
+       public SolutionRevisionBuilder forSolution(String theSolutionId) {
+               this.revision.setSolutionId(theSolutionId);
+               return this;
+       }
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/Updater.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/Updater.java
new file mode 100644 (file)
index 0000000..df0b6b8
--- /dev/null
@@ -0,0 +1,31 @@
+/*-
+ * ===============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.cds;
+
+
+/**
+ */
+@FunctionalInterface
+public interface Updater<R,T> {
+
+       public R update(T... theArgs);
+
+}
+
index 5b8df19..461abb2 100644 (file)
@@ -28,25 +28,27 @@ import java.util.Map;
 
 import org.acumos.cds.transport.RestPageRequest;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+
 import org.apache.http.client.HttpClient;
+
 import org.springframework.boot.web.client.RestTemplateBuilder;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
- * 
- * 
- * 
- * Temporary Client until we have login functions available in Common Data
- * MicroService
+ * Support class for building clients of other components of the Acumos universe that expose an http based
+ * service interface.
  */
 public abstract class AbstractClient {
 
        protected final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(getClass().getName());
 
-       protected final String baseUrl;
-       protected final RestTemplate restTemplate;
+       protected String baseUrl;
+       protected RestTemplate restTemplate;
 
        /**
         * Builds a restTemplate. If user and pass are both supplied, uses basic HTTP
@@ -58,6 +60,28 @@ public abstract class AbstractClient {
         *            underlying http client
         */
        public AbstractClient(String theTarget, HttpClient theClient) {
+               setTarget(theTarget);
+               this.restTemplate = new RestTemplateBuilder()
+                                                                                                       .requestFactory(new HttpComponentsClientHttpRequestFactory(theClient))
+                                                                                                       .rootUri(this.baseUrl)
+                                                                                                       .build();
+       }
+       
+       public AbstractClient(String theTarget, HttpClient theClient, ObjectMapper theMapper) {
+               setTarget(theTarget);
+               
+               MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
+    messageConverter.setObjectMapper(theMapper); //try to avoid building one every time
+
+               this.restTemplate = new RestTemplateBuilder()
+                                                                                                       .requestFactory(new HttpComponentsClientHttpRequestFactory(theClient))
+                                                                                                       .messageConverters(messageConverter)
+                                                                                                       .rootUri(this.baseUrl)
+                                                                                                       .build();
+       
+       }
+
+       protected void setTarget(String theTarget) {
                if (theTarget == null)
                        throw new IllegalArgumentException("Null URL not permitted");
 
@@ -67,12 +91,9 @@ public abstract class AbstractClient {
                        this.baseUrl = url.toExternalForm();
                }
                catch (MalformedURLException ex) {
-                       throw new RuntimeException("Failed to parse targedt URL", ex);
+                       throw new IllegalArgumentException("Failed to parse target URL", ex);
                }
-
-               this.restTemplate = new RestTemplateBuilder()
-                               .requestFactory(new HttpComponentsClientHttpRequestFactory(theClient)).rootUri(this.baseUrl).build();
-       }
+       }       
 
        /**
         * Builds URI by adding specified path segments and query parameters to the base
index ec9da6a..29bc0ed 100644 (file)
@@ -20,6 +20,9 @@
 
 package org.acumos.federation.gateway.common;
 
+import java.io.IOException;
+import java.util.HashMap;
+
 import org.apache.http.client.HttpClient;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -29,18 +32,26 @@ import org.springframework.context.annotation.Import;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Component;
 import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
 import org.springframework.boot.web.client.RestTemplateBuilder;
 
 import org.acumos.nexus.client.NexusArtifactClient;
 import org.acumos.nexus.client.RepositoryLocation;
 
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.core.DockerClientBuilder;
+
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.config.DockerConfiguration;
 import org.acumos.federation.gateway.config.InterfaceConfiguration;
 import org.acumos.federation.gateway.config.LocalInterfaceConfiguration;
 import org.acumos.federation.gateway.config.FederationInterfaceConfiguration;
+import org.acumos.federation.gateway.cds.Mapper;
 
-import org.acumos.cds.client.CommonDataServiceRestClientImpl;
 import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.cds.client.CommonDataServiceRestClientImpl;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
 
 /**
  * Unique entry point for building clients: peer access clients, cds clients
@@ -57,52 +68,71 @@ public class Clients {
        private LocalInterfaceConfiguration localConfig = null;
        @Autowired
        private FederationInterfaceConfiguration federationConfig = null;
+       @Autowired
+       private DockerConfiguration dockerConfig = null;
 
        private final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(getClass().getName());
 
        public Clients() {
-               log.trace(EELFLoggerDelegate.debugLogger, "Clients::new");
        }
-       
+
        /**
         * @return The standard CDS client
         */
        public ICommonDataServiceRestClient getCDSClient() {
 
+               MappingJackson2HttpMessageConverter cdsMessageConverter = new MappingJackson2HttpMessageConverter();
+    cdsMessageConverter.setObjectMapper(Mapper.build()); //try to avoid building one every time
+
                RestTemplateBuilder builder =
                        new RestTemplateBuilder()
                                .requestFactory(new HttpComponentsClientHttpRequestFactory( 
-                                                                                                       /*(HttpClient)this.appCtx.getBean("localClient")*/
                                                                                                        localConfig.buildClient()))
                                //.rootUri(env.getProperty("cdms.client.url"))
                                .basicAuthorization(env.getProperty("cdms.client.username"),
-                                                                                                               env.getProperty("cdms.client.password"));
+                                                                                                               env.getProperty("cdms.client.password"))
+                               .messageConverters(cdsMessageConverter)
+                               ;
 
                        return new CommonDataServiceRestClientImpl(
                                env.getProperty("cdms.client.url"), builder.build());
-               //return new CommonDataServiceRestClientImpl(
-               //              env.getProperty("cdms.client.url"),
-               //              env.getProperty("cdms.client.username"),
-               //              env.getProperty("cdms.client.password"));
        }
 
        /**
         * Build a client for the given peer uri
         */
        public FederationClient getFederationClient(String thePeerURI) {
-               return new FederationClient(thePeerURI, /*(HttpClient)this.appCtx.getBean("federationClient")*/federationConfig.buildClient());
+               return new FederationClient(thePeerURI, federationConfig.buildClient(), Mapper.build());
        }
 
        /** */
        public NexusArtifactClient getNexusClient() {
                RepositoryLocation repositoryLocation = new RepositoryLocation();
 
-               repositoryLocation.setId("1");
+               log.info(EELFLoggerDelegate.debugLogger, "Building Nexus client with {}, {}", env.getProperty("nexus.url"), env.getProperty("nexus.username")); 
 
+               repositoryLocation.setId("1");
                repositoryLocation.setUrl(env.getProperty("nexus.url"));
                repositoryLocation.setUsername(env.getProperty("nexus.username"));
                repositoryLocation.setPassword(env.getProperty("nexus.password"));
                repositoryLocation.setProxy(env.getProperty("nexus.proxy"));
                return new NexusArtifactClient(repositoryLocation);
        }
+
+       /** */
+       public Object getNexusProperty(String theName) {
+               return env.getProperty("nexus." + theName);
+       }
+
+       /** */
+       public DockerClient     getDockerClient() {
+    return DockerClientBuilder.getInstance(dockerConfig.buildConfig())
+                       .withDockerCmdExecFactory(DockerClientBuilder.getDefaultDockerCmdExecFactory())
+                       .build();
+       }
+
+       /** */
+       public Object getDockerProperty(String theName) {
+               return env.getProperty("docker." + theName);
+       }
 }
index b0ab29c..fa02ecf 100644 (file)
@@ -33,7 +33,9 @@ import org.acumos.federation.gateway.common.API;
 import org.acumos.federation.gateway.common.JsonResponse;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.util.Utils;
+
 import org.apache.http.client.HttpClient;
+
 import org.springframework.core.ParameterizedTypeReference;
 import org.springframework.core.io.Resource;
 import org.springframework.http.HttpMethod;
@@ -41,12 +43,9 @@ import org.springframework.http.ResponseEntity;
 import org.springframework.util.Base64Utils;
 import org.springframework.web.client.HttpStatusCodeException;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+
 /**
- * 
- * 
- * 
- * Temporary Client until we have login functions available in Common Data
- * MicroService
  */
 public class FederationClient extends AbstractClient {
 
@@ -60,6 +59,10 @@ public class FederationClient extends AbstractClient {
                super(theTarget, theClient);
        }
 
+       public FederationClient(String theTarget, HttpClient theClient, ObjectMapper theMapper) {
+               super(theTarget, theClient, theMapper);
+       }
+
        /**
         * @return Ping information from/for Remote Acumos
         * @throws HttpStatusCodeException
index 908f297..522a3f7 100644 (file)
 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.
+* This class represents a common format set for the response send to the client over
+* the REST interface.
 */
 
 import java.io.Serializable;
index a2b43e8..c546d98 100644 (file)
@@ -33,13 +33,17 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
 import org.acumos.federation.gateway.service.PeerService;
+import org.acumos.federation.gateway.service.ArtifactService;
 import org.acumos.federation.gateway.service.LocalWatchService;
 
+import org.acumos.federation.gateway.service.impl.ArtifactServiceImpl;
+import org.acumos.federation.gateway.service.impl.ArtifactServiceLocalImpl;
 import org.acumos.federation.gateway.service.impl.CatalogServiceLocalImpl;
 import org.acumos.federation.gateway.service.impl.PeerServiceLocalImpl;
 import org.acumos.federation.gateway.common.Clients;
 
 import org.acumos.federation.gateway.task.TaskConfiguration;
+import org.acumos.federation.gateway.security.AuthenticationConfiguration;
 
 /**
  * Specifies common configuration required by the federation adapter.
@@ -47,11 +51,11 @@ import org.acumos.federation.gateway.task.TaskConfiguration;
  * not specified.
  */
 @Configuration
-//@EnableAutoConfiguration
-@Import(TaskConfiguration.class)
+@Import({TaskConfiguration.class,
+                                AuthenticationConfiguration.class})
 @EnableConfigurationProperties({FederationInterfaceConfiguration.class,
-                                                                                                                               LocalInterfaceConfiguration.class})
-//@Profile({"adapter"})
+                                                                                                                               LocalInterfaceConfiguration.class,
+                                                                                                                               DockerConfiguration.class})
 @Conditional({AdapterCondition.class})
 @EnableScheduling
 public abstract class AdapterConfiguration  {
@@ -70,15 +74,19 @@ public abstract class AdapterConfiguration  {
        
        @Bean
        public PeerSubscriptionService peerSubscriptionService() {
-       //      return new PeerServiceLocalImpl(); //another instance ??
                return this.peerSubSrv;
        }
 
        @Bean
-       public LocalWatchService watchService() {
-               return new LocalWatchService();
+       public ArtifactService localArtifactService() {
+               return new ArtifactServiceLocalImpl();
        }
 
+  @Bean
+  public LocalWatchService watchService() {
+    return new LocalWatchService();
+  }
+
        @Bean
        public Clients clients() {
                return new Clients();
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/DockerConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/config/DockerConfiguration.java
new file mode 100644 (file)
index 0000000..0ff5106
--- /dev/null
@@ -0,0 +1,92 @@
+/*-
+ * ===============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.springframework.stereotype.Component;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import com.github.dockerjava.core.DockerClientConfig; 
+import com.github.dockerjava.core.DefaultDockerClientConfig; 
+
+/**
+ * 
+ */
+@Component
+@ConfigurationProperties(prefix = "docker")
+public class DockerConfiguration {
+
+       private DefaultDockerClientConfig.Builder builder;
+
+       public DockerConfiguration() {
+               reset();
+       }
+
+       private void reset() {
+               this.builder = DefaultDockerClientConfig.createDefaultConfigBuilder();
+       }
+
+       public void setHost(String theHost) {
+               builder.withDockerHost(theHost);
+       }
+
+       public void setApiVersion(String theVersion) {
+               builder.withApiVersion(theVersion);
+  }
+
+       public void setRegistryUsername(String theUsername) {
+               builder.withRegistryUsername(theUsername);
+       }
+
+       public void setRegistryPassword(String thePassword) {
+               builder.withRegistryPassword(thePassword);
+       }
+
+       public void setRegistryEmail(String theEmail) {
+               builder.withRegistryEmail(theEmail);
+       }
+
+       public void setRegistryUrl(String theUrl) {
+               builder.withRegistryUrl(theUrl);
+       }
+
+       public void setDockerCertPath(String thePath) {
+               builder.withDockerCertPath(thePath);
+       }
+
+       public void setDockerConfig(String theConfig) {
+               builder.withDockerConfig(theConfig);
+       }
+
+       public void setDockerTlsVerify(Boolean doVerify) {
+               builder.withDockerTlsVerify(doVerify);
+  }
+
+       /*
+       public void withCustomSslConfig(SSLConfig customSslConfig) {
+       }
+       */
+
+       public DockerClientConfig buildConfig() {
+               return this.builder.build();
+       }
+
+}
index f09f3ac..bfceb0f 100644 (file)
@@ -49,9 +49,7 @@ import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletCon
  * Provide those beans used in the interaction with other peers (federation)
  */
 @Configuration
-@Import(AuthenticationConfiguration.class)
 @EnableAutoConfiguration
-//@ConfigurationProperties(prefix = "federation", ignoreInvalidFields = true)
 public class FederationConfiguration {
 
        @Autowired
@@ -98,15 +96,6 @@ public class FederationConfiguration {
                return this.interfaceConfig.buildClient();
        }
 
-/*
-       @Bean
-       public EmbeddedServletContainerFactory federationServer() {
-               TomcatEmbeddedServletContainerFactory tomcat =
-                       new TomcatEmbeddedServletContainerFactory();
-               tomcat.addAdditionalTomcatConnectors(this.interfaceConfig.buildConnector());
-               return tomcat;
-       }
-*/
        @Bean
        public EmbeddedServletContainerCustomizer federationServer() {
                log.debug(EELFLoggerDelegate.debugLogger, this + "::federationServer from " + this.interfaceConfig);
index 24b5940..50ff17e 100644 (file)
@@ -33,26 +33,32 @@ import org.springframework.scheduling.annotation.EnableScheduling;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
 import org.acumos.federation.gateway.service.PeerService;
+import org.acumos.federation.gateway.service.ArtifactService;
 
 import org.acumos.federation.gateway.service.impl.CatalogServiceImpl;
 import org.acumos.federation.gateway.service.impl.PeerSubscriptionServiceImpl;
 import org.acumos.federation.gateway.service.impl.PeerServiceImpl;
+import org.acumos.federation.gateway.service.impl.ArtifactServiceImpl;
+import org.acumos.federation.gateway.service.impl.ArtifactServiceLocalImpl;
 import org.acumos.federation.gateway.common.Clients;
 
 import org.acumos.federation.gateway.adapter.PeerGateway;
 
 import org.acumos.federation.gateway.task.TaskConfiguration;
+import org.acumos.federation.gateway.security.AuthenticationConfiguration;
 
 
 /**
  * Specifies common configuration required by the federation gateway.
  * Lists/provides all the beans required in running a federation gateway.
+ * 
  */
 @Configuration
-//@EnableAutoConfiguration
-@Import(TaskConfiguration.class)
+@Import({TaskConfiguration.class,
+                                AuthenticationConfiguration.class})
 @EnableConfigurationProperties({FederationInterfaceConfiguration.class,
-                                                                                                                               LocalInterfaceConfiguration.class})
+                                                                                                                               LocalInterfaceConfiguration.class,
+                                                                                                                               DockerConfiguration.class})
 @Conditional({GatewayCondition.class})
 @EnableScheduling
 public class GatewayConfiguration {
@@ -77,6 +83,23 @@ public class GatewayConfiguration {
                return new PeerSubscriptionServiceImpl();
        }
 
+       /**
+        * The 'local' profile allows us to run a gateway based on a local artifact supplier, for testing purposes.
+
+        */
+       @Bean
+       @Profile({"!local"})
+       public ArtifactService artifactService() {
+               return new ArtifactServiceImpl();
+       }
+
+       @Bean
+       @Profile({"local"})
+       public ArtifactService localArtifactService() {
+               return new ArtifactServiceLocalImpl();
+       }
+
+
        @Bean
        public Clients clients() {
                return new Clients();
index 84c7514..172deb2 100644 (file)
@@ -50,10 +50,8 @@ import org.acumos.federation.gateway.security.AuthenticationConfiguration;
  * Provides the beans used in interactions with the local Acumos system
  */
 @Configuration
-@Import(AuthenticationConfiguration.class)
 @EnableAutoConfiguration
-//@ConfigurationProperties(prefix = "local", ignoreInvalidFields = true)
-public class LocalConfiguration /* implements ApplicationContextAware */ {
+public class LocalConfiguration {
 
        @Autowired
        private LocalInterfaceConfiguration interfaceConfig;
@@ -101,16 +99,6 @@ public class LocalConfiguration /* implements ApplicationContextAware */ {
         * Build a servlet container running on the local interface for serving
         * local interface requests (see controllers built here).
         */
-       /*
-       @Bean
-       public EmbeddedServletContainerFactory localServer() {
-               TomcatEmbeddedServletContainerFactory tomcat =
-                       new TomcatEmbeddedServletContainerFactory();
-               tomcat.addAdditionalTomcatConnectors(this.interfaceConfig.buildConnector());
-               return tomcat;
-       }
-       */
-
        @Bean
        public EmbeddedServletContainerCustomizer localServer() {
                log.debug(EELFLoggerDelegate.debugLogger, this + "::localServer from " + this.interfaceConfig);
index 8916033..a994c84 100644 (file)
@@ -25,6 +25,7 @@ import java.net.URISyntaxException;
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.Callable;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,14 +33,17 @@ import javax.servlet.http.HttpServletResponse;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.federation.gateway.cds.ArtifactType;
 import org.acumos.federation.gateway.common.API;
 import org.acumos.federation.gateway.common.JSONTags;
 import org.acumos.federation.gateway.common.JsonResponse;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.security.Peer;
 import org.acumos.federation.gateway.service.CatalogService;
+import org.acumos.federation.gateway.service.ArtifactService;
 import org.acumos.federation.gateway.service.ServiceContext;
 import org.acumos.federation.gateway.util.Utils;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.InputStreamResource;
 import org.springframework.http.MediaType;
@@ -56,6 +60,8 @@ import org.springframework.web.bind.annotation.ResponseBody;
 
 import io.swagger.annotations.ApiOperation;
 
+import com.github.dockerjava.api.model.Identifier;
+
 /**
  * 
  *
@@ -68,6 +74,8 @@ public class CatalogController extends AbstractController {
 
        @Autowired
        private CatalogService catalogService;
+       @Autowired
+       private ArtifactService artifactService;
 
        /**
         * @param theHttpResponse
@@ -255,10 +263,8 @@ public class CatalogController extends AbstractController {
                                API.Paths.SOLUTION_REVISION_ARTIFACTS + "(" + theSolutionId + "," + theRevisionId + ")");
                try {
                        solutionRevisionArtifacts = catalogService.getSolutionRevisionArtifacts(theSolutionId, theRevisionId, context);
-                       if (solutionRevisionArtifacts != null &&
-                                       !context.getPeer().getPeerInfo().isLocal()) {
-                               // re-encode the artifact uri
-                               for (MLPArtifact artifact : solutionRevisionArtifacts) {
+                       for (MLPArtifact artifact : solutionRevisionArtifacts) {
+                               if (!context.getPeer().getPeerInfo().isLocal()) {
                                        encodeArtifact(artifact, theHttpRequest);
                                }
                        }
@@ -295,28 +301,28 @@ public class CatalogController extends AbstractController {
        @RequestMapping(value = {
                        API.Paths.ARTIFACT_DOWNLOAD }, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
        @ResponseBody
-       public InputStreamResource downloadSolutionArtifact(HttpServletRequest theHttpRequest,
+       public Callable<InputStreamResource> downloadSolutionArtifact(HttpServletRequest theHttpRequest,
                        HttpServletResponse theHttpResponse, @PathVariable("artifactId") String theArtifactId) {
-               InputStreamResource resource = null;
-               try {
-                       resource = catalogService.getSolutionRevisionArtifactContent(theArtifactId,
-                                       new ControllerContext());
-                       if (resource == null) {
-                               theHttpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-                       }
-                       else {
-                               theHttpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
-                               theHttpResponse.setHeader("Pragma", "no-cache");
-                               theHttpResponse.setHeader("Expires", "0");
-                               theHttpResponse.setStatus(HttpServletResponse.SC_OK);
+                       
+               theHttpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
+               theHttpResponse.setHeader("Pragma", "no-cache");
+               theHttpResponse.setHeader("Expires", "0");
+               theHttpResponse.setStatus(HttpServletResponse.SC_OK);
+
+               final ControllerContext ctx = new ControllerContext();
+               return new Callable<InputStreamResource>() {
+                       public InputStreamResource call() throws Exception {
+                               try {   
+                                       return artifactService.getArtifactContent(
+                                                                       catalogService.getSolutionRevisionArtifact(theArtifactId, ctx), ctx);
+                               } 
+                               catch (Exception x) {
+                                       log.error(EELFLoggerDelegate.errorLogger,
+                                               "An error occurred while retrieving artifact content " + theArtifactId, x);
+                                       throw x;
+                               }
                        }
-               } 
-               catch (Exception x) {
-                       theHttpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-                       log.error(EELFLoggerDelegate.errorLogger,
-                                       "An error occurred while downloading artifact " + theArtifactId, x);
-               }
-               return resource;
+               };
        }
 
        /** */
@@ -335,16 +341,31 @@ public class CatalogController extends AbstractController {
        
        /** */
        private void encodeArtifact(MLPArtifact theArtifact, HttpServletRequest theRequest) throws URISyntaxException {
-               if (theArtifact.getUri() != null) {
+
+               String artifactUri = theArtifact.getUri();
+
+               //redirect              
+               {
                        URI requestUri = new URI(theRequest.getRequestURL().toString());
-                       URI artifactUri = API.ARTIFACT_DOWNLOAD
+                       URI redirectUri = API.ARTIFACT_DOWNLOAD
                                                                                                .buildUri(
                                                                                                        new URI(requestUri.getScheme(), null, requestUri.getHost(),
                                                                                                                                        requestUri.getPort(), null, null, null).toString(),
                                                                                                        theArtifact.getArtifactId());
-                       log.debug(EELFLoggerDelegate.debugLogger,       "getSolutionRevisionArtifacts: encoded content uri " + artifactUri);
-                       theArtifact.setUri(artifactUri.toString());
+                       log.debug(EELFLoggerDelegate.debugLogger,       "getSolutionRevisionArtifacts: redirected artifact uri " + redirectUri);
+                       theArtifact.setUri(redirectUri.toString());
+               }
+               
+               if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
+                       if (artifactUri != null) {
+                               Identifier imageId = Identifier.fromCompoundString(artifactUri);
+                       
+                               String imageTag = imageId.tag.get(); //there should always be a tag, right??
+                               log.debug(EELFLoggerDelegate.debugLogger,       "getSolutionRevisionArtifacts: encoded docker image uri to tag " + imageTag);
+                               theArtifact.setName(imageTag);
+                               theArtifact.setDescription(imageTag);
+                       }
                }
        }
-
+       
 }
index 5548cb6..b8c3491 100644 (file)
@@ -20,7 +20,8 @@
 
 package org.acumos.federation.gateway.controller;
 
-import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -32,12 +33,29 @@ import org.acumos.federation.gateway.service.ServiceContext;
 import org.acumos.federation.gateway.security.Peer;
 
 /**
- * 
- *
+ * The security context is thread local so we do the same for attributes.
+ * There is a risk when attribute are not cleared and processing threads are pooled.
  */
 public class ControllerContext implements ServiceContext {
 
+       private ThreadLocal<Map<String, Object>> attributes =
+               new ThreadLocal<Map<String, Object>>() {
+                       public Map<String, Object> initialValue() {
+                               return new HashMap<String, Object>();
+                       }
+               };                                                                                                                                                              
+
        public Peer getPeer() {
                return (Peer) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        }
+       
+       public ServiceContext withAttribute(String theName, Object theValue) {
+               attributes.get().put(theName, theValue);
+               return this;
+       }
+
+       public Object getAttribute(String theName) {
+               return attributes.get().get(theName);
+       }
+       
 }
index d121d66..9077c60 100644 (file)
@@ -37,6 +37,8 @@ import org.acumos.federation.gateway.util.Utils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.context.annotation.Scope;
 import org.springframework.context.annotation.Configuration;
 
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
@@ -105,16 +107,6 @@ public class AuthenticationConfiguration extends WebSecurityConfigurerAdapter {
                                                        .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                                        .and()
                                                .x509()
-                                                       //.x509AuthenticationFilter(new X509AuthenticationFilter() {
-                                                       //              {
-                                                       //                      System.out.println(" *** Set custom principal extractor");
-                                                       //                      setPrincipalExtractor((cert) -> {
-                                                       //                              System.out.println(" *** got principal: " + cert.getSubjectX500Principal().getName());
-                                                       //                              return cert.getSubjectX500Principal().getName(); 
-                                                       //                      });
-                                                       //              }
-                                                       //      })
-                                                       //.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
                                                        .subjectPrincipalRegex("(.*)")  //select whole subject line
                                                        .userDetailsService(userDetailsService());
        }
@@ -128,6 +120,12 @@ public class AuthenticationConfiguration extends WebSecurityConfigurerAdapter {
                });
        }
 
+       @Bean
+       @Lazy
+       public Peer self() {
+               return new Peer(peerService.getSelf(), Role.SELF.priviledges());
+       }
+
        /** */
        @Bean
        public UserDetailsService userDetailsService() {
@@ -170,6 +168,7 @@ public class AuthenticationConfiguration extends WebSecurityConfigurerAdapter {
                        log.info(EELFLoggerDelegate.debugLogger, " Peers matching X509 subject : " + mlpPeers);
                        if (!Utils.isEmptyList(mlpPeers)) {
                                MLPPeer mlpPeer = mlpPeers.get(0);
+                               //!!here we create other instances of 'self'
                                return new Peer(mlpPeer, mlpPeer.isSelf() ? Role.SELF : Role.PEER);
                        }
                        else {
index 72aaedb..3ec9b4a 100644 (file)
@@ -24,9 +24,6 @@ import java.util.Collection;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.userdetails.User;
 
-import org.springframework.beans.factory.annotation.Autowired;
-
-import org.acumos.federation.gateway.service.PeerService;
 import org.acumos.federation.gateway.cds.PeerStatus;
 
 import org.acumos.cds.domain.MLPPeer;
@@ -51,35 +48,4 @@ public class Peer extends User {
                return this.peerInfo;
        }
 
-//     @Override
-//     public boolean isEnabled() {
-//             if (this.peerInfo == null)
-//                     return false;
-
-//             PeerStatus peerStatus =  PeerStatus.forCode(this.peerInfo.getStatusCode());
-//             return peerStatus == PeerStatus.Active;
-//     }
-
-       private static PeerService peerService = null;
-
-       @Autowired
-       public void setPeerService(PeerService thePeerService) {
-               if (peerService != null)
-                       throw new IllegalStateException("Already set");
-
-               peerService = thePeerService;
-       }
-
-       private static Peer self = null;
-
-       public static Peer self() {
-               if (self == null) {
-                       if (peerService == null)
-                               throw new IllegalStateException("Initialization not completed");
-                       self = new Peer(peerService.getSelf(), Role.SELF.priviledges());
-               }
-
-               return self;
-       }
-
 }
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/ArtifactService.java b/gateway/src/main/java/org/acumos/federation/gateway/service/ArtifactService.java
new file mode 100644 (file)
index 0000000..9ad4943
--- /dev/null
@@ -0,0 +1,56 @@
+/*-
+ * ===============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.service;
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.InputStreamResource;
+
+import org.acumos.cds.domain.MLPArtifact;
+
+/**
+ * Handles access to the artifacts repository. 
+ */
+public interface ArtifactService {
+
+       /**
+        * @param theArtifact
+        *            The CDS representation of artifact metadata
+        * @param theContext
+        *            the execution context
+        * @return resource containing access to the actual artifact content
+        */
+       public InputStreamResource getArtifactContent(MLPArtifact theArtifact, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException;
+
+
+       /**
+        * If the call is succesful the artifact information is updated with the content uri.
+        * No service context here as this call is always used with respect to the local gateway instance.
+        * @param theArtifact
+        *            The CDS representation of artifact metadata
+        * @param theResource
+        *            the resource providing the artifact content
+        */
+       public void putArtifactContent(MLPArtifact theArtifact, Resource theResource) throws ServiceException;
+}
index ccf1ff0..e28272c 100644 (file)
@@ -53,9 +53,11 @@ public interface CatalogService {
         * @param theContext
         *            the execution context.
         * 
-        * @return List of the Catalog Solutions for the selection criteria
+        * @return List of the Catalog Solutions for the selection criteria. An empty list is returned when no
+        * solutions satisfy the criteria.
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext);
+       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException;
 
        /**
         * Default interface for calls in behalf of the local Acumos service.
@@ -63,10 +65,12 @@ public interface CatalogService {
         * @param theSelector
         *            contains the selection criteria. Must match the available criteria
         *            in CDS
-        * @return list of the solutions for the selection criteria
+        * @return List of the Catalog Solutions for the selection criteria. An empty list is returned when no
+        * solutions satisfy the criteria.
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public default List<MLPSolution> getSolutions(Map<String, ?> theSelector) {
-               return getSolutions(theSelector, ServiceContext.selfService());
+       public default List<MLPSolution> getSolutions(Map<String, ?> theSelector) throws ServiceException {
+               return getSolutions(theSelector, selfService());
        }
 
        /**
@@ -76,9 +80,10 @@ public interface CatalogService {
         *            solution identifier (UUID).
         * @param theContext
         *            the execution context
-        * @return solution information
+        * @return solution information. Will return null if the given solution id does not match an existing solution;
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public MLPSolution getSolution(String theSolutionId, ServiceContext theContext);
+       public MLPSolution getSolution(String theSolutionId, ServiceContext theContext) throws ServiceException ;
 
        /**
         * Default solution access interface for calls in behalf of the local Acumos
@@ -87,9 +92,10 @@ public interface CatalogService {
         * @param theSolutionId
         *            solution identifier (UUID).
         * @return solution information
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public default MLPSolution getSolution(String theSolutionId) {
-               return getSolution(theSolutionId, ServiceContext.selfService());
+       public default MLPSolution getSolution(String theSolutionId) throws ServiceException {
+               return getSolution(theSolutionId, selfService());
        }
 
        /**
@@ -99,12 +105,14 @@ public interface CatalogService {
         *            identifier of the solution whose revisions are to be provided
         * @param theContext
         *            the execution context
-        * @return list of the solution revision for the specified solution Id
+        * @return list of the solution revision for the specified solution Id. Will return an empty list if the
+        * given solution does not have revisions. Null is return if no solution with the given id exists.
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext);
+       public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext) throws ServiceException ;
 
-       public default List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId) {
-               return getSolutionRevisions(theSolutionId, ServiceContext.selfService());
+       public default List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId) throws ServiceException {
+               return getSolutionRevisions(theSolutionId, selfService());
        }
 
        /**
@@ -117,9 +125,10 @@ public interface CatalogService {
         * @param theContext
         *            the execution context
         * @return solution revision information
+        * @throws ServiceException if an error is encoutered during processing
         */
        public MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId,
-                       ServiceContext theContext);
+                       ServiceContext theContext) throws ServiceException ;
 
        /**
         * Default solution revision access interface for calls in behalf of the local
@@ -130,9 +139,10 @@ public interface CatalogService {
         * @param theRevisionId
         *            revision identifier (UUID).
         * @return solution revision information
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public default MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId) {
-               return getSolutionRevision(theSolutionId, theRevisionId, ServiceContext.selfService());
+       public default MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId) throws ServiceException {
+               return getSolutionRevision(theSolutionId, theRevisionId, selfService());
        }
 
        /**
@@ -144,10 +154,11 @@ public interface CatalogService {
         *            revision identifier (UUID).
         * @param theContext
         *            the execution context
-        * @return list of the related artifacts
+        * @return list of the related artifacts. Null is returned if the solution id or the revision id do not indicate existing items.
+        * @throws ServiceException if an error is encoutered during processing
         */
        public List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId,
-                       ServiceContext theContext);
+                       ServiceContext theContext) throws ServiceException;
 
        /**
         * Default solution revision access interface for calls in behalf of the local
@@ -158,9 +169,10 @@ public interface CatalogService {
         * @param theRevisionId
         *            revision identifier (UUID).
         * @return list of the related artifacts
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public default List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId) {
-               return getSolutionRevisionArtifacts(theSolutionId, theRevisionId, ServiceContext.selfService());
+       public default List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId) throws ServiceException {
+               return getSolutionRevisionArtifacts(theSolutionId, theRevisionId, selfService());
        }
 
        /**
@@ -171,9 +183,29 @@ public interface CatalogService {
         *            retrieved
         * @param theContext
         *            the execution context
-        * @return resource containing access to the actual artifact content
+        * @return the artifact information
+        * @throws ServiceException if an error is encoutered during processing
         */
-       public InputStreamResource getSolutionRevisionArtifactContent(String theArtifactId, ServiceContext theContext)
+       public MLPArtifact getSolutionRevisionArtifact(String theArtifactId, ServiceContext theContext)
                                                                                                                                                                                                                                                                                                                                                                        throws ServiceException;
 
+       /**
+        * Retrieve artifact content.
+        *
+        * @param theArtifactId
+        *            identifier of the acumos artifact whose content needs to be
+        *            retrieved
+        * @return the artifact information
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public default MLPArtifact getSolutionRevisionArtifact(String theArtifactId) throws ServiceException {
+               return getSolutionRevisionArtifact(theArtifactId, selfService());
+       }
+
+       /**
+        * This would belong as a static method of ServiceContext but ServicrCOntext are not beans so I cannot wire them to access the
+        * self bean; in here it exposes an implementation detail which is ugly ..
+        */
+       public ServiceContext selfService();
+
 }
index aa97776..173437a 100644 (file)
@@ -56,7 +56,7 @@ public interface PeerService {
         * @return list of peers for the local acumoms system
         */
        public default List<MLPPeer> getPeers() {
-               return getPeers(ServiceContext.selfService());
+               return getPeers(selfService());
        }
 
        /**
@@ -81,7 +81,7 @@ public interface PeerService {
         *         entry.
         */
        public default List<MLPPeer> getPeerBySubjectName(String theSubjectName) {
-               return getPeerBySubjectName(theSubjectName, ServiceContext.selfService());
+               return getPeerBySubjectName(theSubjectName, selfService());
        }
 
        /**
@@ -104,7 +104,7 @@ public interface PeerService {
         * @return peer information
         */
        public default MLPPeer getPeerById(String thePeerId) {
-               return getPeerById(thePeerId, ServiceContext.selfService());
+               return getPeerById(thePeerId, selfService());
        }
 
        /**
@@ -131,4 +131,9 @@ public interface PeerService {
         */
        public void unregisterPeer(MLPPeer thePeer) throws ServiceException;
 
+       /**
+        * Provide a context for self service calls, ie calls made on the behalf of the gateway itself.
+        */
+       public ServiceContext selfService();
+
 }
index a4d5cf4..4e43981 100644 (file)
@@ -47,9 +47,7 @@ public interface PeerSubscriptionService {
        /**
         * @param mlpPeerSubscription
         *            MLPPeer Configuration that needs to be updated on the Platform
-        * 
-        * @return MLPPeerSubscription configuration that has been updated.
         */
-       boolean updatePeerSubscription(MLPPeerSubscription mlpPeerSubscription);
+       void updatePeerSubscription(MLPPeerSubscription mlpPeerSubscription) throws ServiceException;
 
 }
index 864d201..de9519d 100644 (file)
  * limitations under the License.
  * ===============LICENSE_END=========================================================
  */
-
-/**
- * 
- */
 package org.acumos.federation.gateway.service;
 
+import java.util.Map;
+import java.util.HashMap;
+
 import org.acumos.federation.gateway.security.Peer;
 
 /**
@@ -31,6 +30,14 @@ import org.acumos.federation.gateway.security.Peer;
  */
 public interface ServiceContext {
 
+       /*
+        */
+       public ServiceContext withAttribute(String theName, Object theValue);
+
+       /*
+        */
+       public Object getAttribute(String theName);
+
        /*
         * In who's behalf are we providing the service.
         */
@@ -44,9 +51,33 @@ public interface ServiceContext {
        }
 
        /*
-        * Only feasible for as long as this interface is down to 'getPeer'
         */
-       public static ServiceContext selfService() {
-               return () -> Peer.self();
+       //public static ServiceContext selfService() {
+       //      return forPeer(/*how to get a reference to the self peer in here ??*/);
+       //}
+
+       /*
+        */
+       public static ServiceContext forPeer(final Peer thePeer) {
+               return new ServiceContext() {
+
+                       private Map<String, Object> attributes = new HashMap<String, Object>();
+                       private Peer                                                            peer;
+
+                       {
+                               peer = thePeer;
+                       }
+
+                       public Peer getPeer() { return peer; }
+
+                       public ServiceContext withAttribute(String theName, Object theValue) {
+                               attributes.put(theName, theValue);
+                               return this;
+                       }
+
+                       public Object getAttribute(String theName) {
+                               return attributes.get(theName);
+                       }
+               };
        }
 }
index 1345d06..c9bae86 100644 (file)
 
 package org.acumos.federation.gateway.service.impl;
 
+import org.springframework.context.ApplicationContext;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.common.Clients;
+import org.acumos.federation.gateway.service.ServiceContext;
+import org.acumos.federation.gateway.security.Peer;
 
 import org.acumos.cds.client.ICommonDataServiceRestClient;
 
@@ -32,11 +35,14 @@ public abstract class AbstractServiceImpl {
 
        @Autowired
        protected Clients clients;
-
-       protected final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(getClass().getName());
+       @Autowired
+       protected ApplicationContext appCtx;
 
        public ICommonDataServiceRestClient getClient() {
                return clients.getCDSClient();
        }
 
+       public ServiceContext selfService() {
+               return ServiceContext.forPeer((Peer)appCtx.getBean("self"));            
+       }
 }
index 62d52a9..088c7a1 100644 (file)
@@ -29,14 +29,16 @@ import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Conditional;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import org.acumos.federation.gateway.service.ServiceContext;
+import org.acumos.federation.gateway.security.Peer;
 import org.acumos.federation.gateway.service.LocalWatchService;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 
 import org.apache.commons.io.IOUtils;
 
+
 public class AbstractServiceLocalImpl {
 
-       protected EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(getClass().getName());
        protected Resource resource;
 
        @Autowired
@@ -60,4 +62,7 @@ public class AbstractServiceLocalImpl {
                }
        }
 
+       public ServiceContext selfService() {
+               return ServiceContext.forPeer((Peer)appCtx.getBean("self"));            
+       }
 }
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceImpl.java b/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceImpl.java
new file mode 100644 (file)
index 0000000..ec3043f
--- /dev/null
@@ -0,0 +1,170 @@
+/*-
+ * ===============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.service.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Date;
+import java.util.stream.Collectors;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.io.FileUtils;
+
+import org.acumos.federation.gateway.cds.ArtifactType;
+import org.acumos.federation.gateway.util.Utils;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ServiceContext;
+import org.acumos.federation.gateway.service.ServiceException;
+
+import org.acumos.nexus.client.NexusArtifactClient;
+import org.acumos.nexus.client.data.UploadArtifactInfo;
+
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.model.Identifier;
+import com.github.dockerjava.api.model.Repository;
+import com.github.dockerjava.core.command.PullImageResultCallback;
+import com.github.dockerjava.core.command.PushImageResultCallback;
+
+import org.acumos.cds.AccessTypeCode;
+import org.acumos.cds.ValidationStatusCode;
+import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.cds.domain.MLPArtifact;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.stereotype.Service;
+import org.springframework.context.annotation.Conditional;
+
+
+/**
+ * CDS based implementation of the CatalogService.
+ *
+ */
+@Service
+public class ArtifactServiceImpl extends AbstractServiceImpl
+                                                                                                                                       implements ArtifactService {
+
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(ArtifactServiceImpl.class.getName());
+
+       /**
+        * @return a resource containing the content or null if the artifact has no content
+        * @throws ServiceException if failing to retrieve artifact information or retrieve content 
+        */
+       @Override
+       public InputStreamResource getArtifactContent(MLPArtifact theArtifact, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                                       throws ServiceException {
+               if (theArtifact.getUri() == null) {
+                       throw new ServiceException("No artifact uri available for " + theArtifact);
+               }
+               log.info(EELFLoggerDelegate.debugLogger, "Retrieving artifact content for {}",theArtifact);
+
+               InputStreamResource streamResource = null;
+               try {
+                       if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
+                               //pull followed by save
+                               DockerClient docker = this.clients.getDockerClient();
+
+                               PullImageResultCallback pullResult = new PullImageResultCallback();
+                               docker.pullImageCmd(theArtifact.getUri())
+                                                       .exec(pullResult);
+                               pullResult.awaitCompletion();
+
+                               return new InputStreamResource(docker.saveImageCmd(theArtifact.getName()).exec());
+                       }
+                       else {  
+                               NexusArtifactClient artifactClient = this.clients.getNexusClient();
+                               ByteArrayOutputStream artifactContent = artifactClient.getArtifact(theArtifact.getUri());
+                               log.info(EELFLoggerDelegate.debugLogger, "Retrieved {} bytes of artifact content", artifactContent.size());
+                               streamResource = new InputStreamResource(
+                                                                                                       new ByteArrayInputStream(
+                                                                                                               artifactContent.toByteArray()
+                                                                                               ));
+                       }
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifact content for artifact " + theArtifact, x);
+                       throw new ServiceException("Failed to retrieve artifsact content for artifact " + theArtifact, x);
+               }
+               return streamResource;
+       }
+
+       public void putArtifactContent(MLPArtifact theArtifact, Resource theResource) throws ServiceException {
+               UploadArtifactInfo uploadInfo = null;
+               try {
+                       if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
+                               //load followed by push
+
+                               DockerClient docker = this.clients.getDockerClient();
+
+                               docker.loadImageCmd(theResource.getInputStream())
+                                                       .exec(); //sync xecution
+
+                               // there is an assumption here that the repo info was stripped from the artifact name by the originator
+                               PushImageResultCallback pushResult = new PushImageResultCallback();
+                               Identifier imageId =
+                                       new Identifier(
+                                               new Repository(this.clients.getDockerProperty("registryUrl").toString()),
+                                               theArtifact.getName() /*the tag*/);
+                               docker.pushImageCmd(imageId)
+                                                       .exec(pushResult);
+                               pushResult.awaitCompletion();
+                               
+                               // update artifact with local repo reference. we also update the name and description in order to stay
+                               // alligned with on-boarding's unwritten rules
+                               theArtifact.setUri(imageId.toString());
+                               theArtifact.setName(imageId.toString());
+                               theArtifact.setDescription(imageId.toString());
+                       }
+                       else {
+                               uploadInfo = this.clients.getNexusClient()
+                                                                                       .uploadArtifact((String)this.clients.getNexusProperty("groupId"),
+                                                                                                                                                       theArtifact.getName(), /* probably wrong */
+                                                                                                                                                       theArtifact.getVersion(),
+                                                                                                                                                       "",
+                                                                                                                                                       theResource.contentLength(),
+                                                                                                                                                       theResource.getInputStream());
+                               log.info(EELFLoggerDelegate.debugLogger, "Wrote artifact content to {}", uploadInfo.getArtifactMvnPath());
+                               // update artifact with local repo reference
+                               theArtifact.setUri(uploadInfo.getArtifactMvnPath());
+                       }
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger,
+                                                               "Failed to push artifact content to local Nexus repo", x);
+                       throw new ServiceException("Failed to push artifact content to local Nexus repo", x);
+               }
+
+       }
+}
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceLocalImpl.java b/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceLocalImpl.java
new file mode 100644 (file)
index 0000000..a548c6f
--- /dev/null
@@ -0,0 +1,100 @@
+/*-
+ * ===============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.service.impl;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.util.stream.Collectors;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.io.FileUtils;
+
+import org.acumos.federation.gateway.util.Utils;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ServiceContext;
+import org.acumos.federation.gateway.service.ServiceException;
+
+import org.acumos.cds.domain.MLPArtifact;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.stereotype.Service;
+import org.springframework.context.annotation.Conditional;
+
+import org.apache.commons.io.FileUtils;
+
+/**
+ * File based implementation of the ArtifactService.
+ *
+ */
+@Service
+public class ArtifactServiceLocalImpl extends AbstractServiceImpl
+                                                                                                                                       implements ArtifactService {
+
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(ArtifactServiceLocalImpl.class.getName());
+
+       /**
+        * @return a resource containing the content or null if the artifact has no content
+        * @throws ServiceException if failing to retrieve artifact information or retrieve content 
+        */
+       @Override
+       public InputStreamResource getArtifactContent(MLPArtifact theArtifact, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                                       throws ServiceException {
+               if (theArtifact.getUri() == null) {
+                       throw new ServiceException("No artifact uri available for " + theArtifact);
+               }
+
+               try {
+                       return new InputStreamResource(new URI(theArtifact.getUri()).toURL().openStream());
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifact content for artifact " + theArtifact, x);
+                       throw new ServiceException("Failed to retrieve artifact content for artifact " + theArtifact, x);
+               }
+       }
+
+       /**
+        * Should add a configuration parameter for the location of the file.
+        */
+       public void putArtifactContent(MLPArtifact theArtifact, Resource theResource) throws ServiceException {
+
+               File target = null;
+               try {
+                       target = File.createTempFile(theArtifact.getName() + "-" + theArtifact.getVersion(), null /*""*//*,File directory*/);
+                       FileUtils.copyInputStreamToFile(theResource.getInputStream(), target);
+               }
+               catch (IOException iox) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to write artifact content for artifact " + theArtifact, iox);
+                       throw new ServiceException("Failed to write artifact content for artifact " + theArtifact, iox);
+               }
+
+               theArtifact.setUri(target.toURI().toString());
+       }       
+}
index 6033cb7..5a963d7 100644 (file)
@@ -32,16 +32,19 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Date;
 import java.util.stream.Collectors;
 
 import javax.annotation.PostConstruct;
 
 import org.apache.commons.io.FileUtils;
+
+import org.acumos.federation.gateway.util.Utils;
+import org.acumos.federation.gateway.util.Errors;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.ServiceContext;
 import org.acumos.federation.gateway.service.ServiceException;
-import org.acumos.federation.gateway.util.Utils;
 
 import org.acumos.nexus.client.NexusArtifactClient;
 
@@ -52,20 +55,27 @@ import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
 import org.acumos.cds.transport.RestPageResponse;
+import org.acumos.cds.transport.RestPageRequest;
 
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
 import org.springframework.core.io.InputStreamResource;
 import org.springframework.stereotype.Service;
 import org.springframework.context.annotation.Conditional;
+import org.springframework.web.client.HttpStatusCodeException;
 
+import org.acumos.federation.gateway.cds.Solution;
+import org.acumos.federation.gateway.cds.SolutionRevision;
 
 /**
  * CDS based implementation of the CatalogService.
  *
  */
 @Service
-public class CatalogServiceImpl extends AbstractServiceImpl implements CatalogService {
+public class CatalogServiceImpl extends AbstractServiceImpl
+                                                                                                                               implements CatalogService {
+
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(CatalogServiceImpl.class.getName());
 
        @Autowired
        private Environment env;
@@ -76,95 +86,154 @@ public class CatalogServiceImpl extends AbstractServiceImpl implements CatalogSe
        public void initService() {
                baseSelector = new HashMap<String, Object>();
 
-               baseSelector.put("active", true); // Fetch all active solutions
-               baseSelector.put("accessTypeCode", AccessTypeCode.PB.toString()); // Fetch allowed only for Public models
-               baseSelector.put("validationStatusCode", ValidationStatusCode.PS.toString()); // Validation status should be
-                                                                                                                                                                               // Passed locally
-               // baseSelector.put("source", "");
-
+               // Fetch all active solutions
+               baseSelector.put("active", true);
+               // Fetch allowed only for Public models
+               baseSelector.put("accessTypeCode", AccessTypeCode.PB.toString());
+               // Validation status should be passed locally
+               baseSelector.put("validationStatusCode", ValidationStatusCode.PS.toString());
        }
 
        @Override
-       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) {
-
-               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions");
-               List<MLPSolution> filteredMLPSolutions = null;
-               ICommonDataServiceRestClient cdsClient = getClient();
+       /*
+        */
+       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException {
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions with selector {}", theSelector);
 
-               Map<String, Object> selector = new HashMap<String, Object>(this.baseSelector);
+               Map<String, Object> selector = new HashMap<String, Object>();
                if (theSelector != null)
                        selector.putAll(theSelector);
+               //it is essential that this gets done at the end as to force all baseSelector criteria (otherwise a submitted accessTypeCode
+               //could overwrite the basic one end expose non public solutions ..).
+               selector.putAll(this.baseSelector);
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions with full selector {}", selector);
+
+               RestPageRequest pageRequest = new RestPageRequest(0, 5);
+               RestPageResponse<MLPSolution> pageResponse = null;
+               List<MLPSolution> solutions = new ArrayList<MLPSolution>(),
+                                                                                       pageSolutions = null;
+               ICommonDataServiceRestClient cdsClient = getClient();
 
-               //TODO: load all pages ?? 
-               RestPageResponse<MLPSolution> response = 
-                       getClient().searchSolutions(selector, false, null);
-               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions: cds solutions count {}", response.getSize());
+               do {
+                       log.debug(EELFLoggerDelegate.debugLogger, "getSolutions page {}", pageResponse);
+                       if (theSelector.containsKey("modified")) {
+                               //Use the dedicated api: this is a 'deep' application of the 'modified' criteria as it will look into revisions
+                               //and artifacts for related information modified since.
+                               pageResponse =
+                                       cdsClient.findSolutionsByDate(
+                                               (Boolean)baseSelector.get("active"),
+                                               new String[] {baseSelector.get("accessTypeCode").toString()},
+                                               new String[] {baseSelector.get("validationStatusCode").toString()},
+                                               new Date((Long)theSelector.get("modified")),
+                                               pageRequest);
+                       
+                               //we need to post-process all other selection criteria
+                               pageSolutions = pageResponse.getContent().stream()
+                                                                                                       .filter(solution -> ServiceImpl.isSelectable(solution, theSelector))
+                                                                                                       .collect(Collectors.toList());
+                       }
+                       else {
+                               pageResponse =
+                                       cdsClient.searchSolutions(selector, false, pageRequest);
+                               pageSolutions = pageResponse.getContent();
+                       }
+                       log.debug(EELFLoggerDelegate.debugLogger, "getSolutions page response {}", pageResponse);
+               
+                       pageRequest.setPage(pageResponse.getNumber() + 1);
+                       solutions.addAll(pageSolutions);
+               }
+               while (!pageResponse.isLast());
 
-               return response.getContent();
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions: cds solutions count {}", solutions.size());
+               return solutions;
        }
 
        @Override
-       public MLPSolution getSolution(String theSolutionId, ServiceContext theContext) {
+       public MLPSolution getSolution(String theSolutionId, ServiceContext theContext) throws ServiceException {
 
-               log.trace(EELFLoggerDelegate.debugLogger, "getSolution");
+               log.trace(EELFLoggerDelegate.debugLogger, "getSolution {}", theSolutionId);
                ICommonDataServiceRestClient cdsClient = getClient();
-               return cdsClient.getSolution(theSolutionId);
+               try {
+                       Solution solution = (Solution)cdsClient.getSolution(theSolutionId);
+                       solution.setRevisions(cdsClient.getSolutionRevisions(theSolutionId));
+                       return solution;
+               }
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution information", restx);
+               }
        }
 
        @Override
-       public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext) {
+       public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext) throws ServiceException {
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisions");
-               ICommonDataServiceRestClient cdsClient = getClient();
-               List<MLPSolutionRevision> mlpSolutionRevisions = cdsClient.getSolutionRevisions(theSolutionId);
-               return mlpSolutionRevisions;
+               try {
+                       return getClient().getSolutionRevisions(theSolutionId);
+               }
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution revision information", restx);
+               }
        }
 
        @Override
        public MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId,
-                       ServiceContext theContext) {
+                       ServiceContext theContext) throws ServiceException {
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevision");
                ICommonDataServiceRestClient cdsClient = getClient();
-               MLPSolutionRevision mlpSolutionRevision = cdsClient.getSolutionRevision(theSolutionId, theRevisionId);
-               return mlpSolutionRevision;
+               try {
+                       SolutionRevision revision =
+                                       (SolutionRevision)cdsClient.getSolutionRevision(theSolutionId, theRevisionId);
+                       revision.setArtifacts(cdsClient.getSolutionRevisionArtifacts(theSolutionId, theRevisionId));
+                       return revision;
+               }       
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution revision information", restx);
+               }
        }
 
        @Override
        public List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId,
-                       ServiceContext theContext) {
+                       ServiceContext theContext) throws ServiceException {
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifacts");
-               ICommonDataServiceRestClient cdsClient = getClient();
-               List<MLPArtifact> mlpArtifacts = cdsClient.getSolutionRevisionArtifacts(theSolutionId, theRevisionId);
-               return mlpArtifacts;
+               try {
+                       return getClient().getSolutionRevisionArtifacts(theSolutionId, theRevisionId);
+               }
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution information", restx);
+               }
        }
 
        /**
-        * @return a resource containing the content or null if the artifact has no content
+        * @return catalog artifact representation
         * @throws ServiceException if failing to retrieve artifact information or retrieve content 
         */
        @Override
-       public InputStreamResource getSolutionRevisionArtifactContent(String theArtifactId, ServiceContext theContext) throws ServiceException {
+       public MLPArtifact getSolutionRevisionArtifact(String theArtifactId, ServiceContext theContext) throws ServiceException {
 
-               InputStreamResource streamResource = null;
+               log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifact");
                try {
-                       ICommonDataServiceRestClient cdsClient = getClient();
-                       MLPArtifact artifact = cdsClient.getArtifact(theArtifactId);
-
-                       if (artifact.getUri() != null) {
-                               NexusArtifactClient artifactClient = this.clients.getNexusClient();
-                               streamResource = new InputStreamResource(
-                                                                                                       new ByteArrayInputStream(
-                                                                                                               artifactClient.getArtifact(artifact.getUri()).toByteArray()
-                                                                                                       ));
-                       }
-               }
-               catch (Exception x) {
-                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifact content for artifact " + theArtifactId, x);
-                       throw new ServiceException("Failed to retrieve artifsact content for artifact " + theArtifactId, x);
+                       return getClient().getArtifact(theArtifactId);
+               }       
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution revision artifact information", restx);
                }
-               return streamResource;
        }
 
 }
index c05e6c0..2e2121a 100644 (file)
@@ -34,6 +34,7 @@ import java.util.LinkedList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Collections;
 import java.util.stream.Collectors;
 
 import javax.annotation.PostConstruct;
@@ -78,6 +79,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
 @ConfigurationProperties(prefix = "catalogLocal")
 public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements CatalogService {
 
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(CatalogServiceLocalImpl.class.getName());
+
        private List<FLPSolution> solutions;
 
        @PostConstruct
@@ -118,30 +121,17 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
        }
 
        @Override
-       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) {
+       public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException {
 
-               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions");
-               String modelTypeSelector = theSelector == null ? null : (String) theSelector.get("modelTypeCode");
-               String toolkitTypeSelector = theSelector == null ? null : (String) theSelector.get("toolkitTypeCode");
-               final List<String> modelTypes = modelTypeSelector == null ? null : Arrays.asList(modelTypeSelector.split(","));
-               final List<String> toolkitTypes = toolkitTypeSelector == null ? null : Arrays.asList(toolkitTypeSelector.split(","));
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutions, selector {}", theSelector);
 
                return solutions.stream()
-                       .filter(solution -> {
-                               log.debug(EELFLoggerDelegate.debugLogger,
-                                       "getPeerCatalogSolutionsList: looking for model type " + modelTypes + ", has " + solution.getModelTypeCode());
-                               return modelTypes == null || modelTypes.contains(solution.getModelTypeCode());
-                       })
-                       .filter(solution -> {
-                               log.debug(EELFLoggerDelegate.debugLogger,
-                                       "getPeerCatalogSolutionsList: looking for toolkit type " + toolkitTypes + ", has " + solution.getToolkitTypeCode());
-                               return toolkitTypes == null || toolkitTypes.contains(solution.getToolkitTypeCode());
-                       })
+                       .filter(solution -> ServiceImpl.isSelectable(solution, theSelector))
                        .collect(Collectors.toList());
        }
 
        @Override
-       public MLPSolution getSolution(final String theSolutionId, ServiceContext theContext) {
+       public MLPSolution getSolution(final String theSolutionId, ServiceContext theContext) throws ServiceException {
 
                log.debug(EELFLoggerDelegate.debugLogger, "getSolution");
                return solutions.stream().filter(solution -> {
@@ -150,7 +140,7 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
        }
 
        @Override
-       public List<MLPSolutionRevision> getSolutionRevisions(final String theSolutionId, ServiceContext theContext) {
+       public List<MLPSolutionRevision> getSolutionRevisions(final String theSolutionId, ServiceContext theContext) throws ServiceException {
 
                log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisions");
                FLPSolution solution = this.solutions.stream().filter(sol -> sol.getSolutionId().equals(theSolutionId))
@@ -161,7 +151,7 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
 
        @Override
        public MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId,
-                       ServiceContext theContext) {
+                       ServiceContext theContext) throws ServiceException  {
 
                log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevision");
                List<MLPSolutionRevision> revisions = getSolutionRevisions(theSolutionId, theContext);
@@ -174,7 +164,7 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
 
        @Override
        public List<MLPArtifact> getSolutionRevisionArtifacts(final String theSolutionId, final String theRevisionId,
-                       ServiceContext theContext) {
+                       ServiceContext theContext) throws ServiceException {
                log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifacts");
 
                FLPRevision revision = (FLPRevision) getSolutionRevision(theSolutionId, theRevisionId, theContext);
@@ -183,22 +173,15 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
        }
 
        @Override
-       public InputStreamResource getSolutionRevisionArtifactContent(String theArtifactId, ServiceContext theContext) 
+       public MLPArtifact getSolutionRevisionArtifact(String theArtifactId, ServiceContext theContext) 
                                                                                                                                                                                                                                                                                                                                                                                                throws ServiceException {
-
-               log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifactContent");
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifact");
                // cumbersome
                for (FLPSolution solution : this.solutions) {
                        for (FLPRevision revision : solution.getRevisions()) {
                                for (MLPArtifact artifact : revision.getArtifacts()) {
                                        if (artifact.getArtifactId().equals(theArtifactId)) {
-                                               try {
-                                                       return new InputStreamResource(new URI(artifact.getUri()).toURL().openStream());
-                                               } catch (Exception x) {
-                                                       log.debug(EELFLoggerDelegate.debugLogger,
-                                                                       "failed to load artifact content from " + artifact.getUri(), x);
-                                                       throw new ServiceException("Failed to retrieve content for artifact " + theArtifactId, x);
-                                               }
+                                               return artifact;
                                        }
                                }
                        }
@@ -211,7 +194,7 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
        public static class FLPSolution extends MLPSolution {
 
                @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
-               private List<FLPRevision> revisions;
+               private List<FLPRevision> revisions = Collections.EMPTY_LIST;
 
                // @JsonIgnore
                public List<FLPRevision> getRevisions() {
@@ -234,7 +217,7 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
        public static class FLPRevision extends MLPSolutionRevision {
 
                @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
-               private List<MLPArtifact> artifacts;
+               private List<MLPArtifact> artifacts = Collections.EMPTY_LIST;
 
                // @JsonIgnore
                // we send a deep clone as the client can modify them and we only have one copy
index 97bdd67..d91762f 100644 (file)
 package org.acumos.federation.gateway.service.impl;
 
 import java.util.Collections;
+import java.util.Map;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
-import java.util.Collections;
+import java.util.ArrayList;
 
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.util.MapBuilder;
@@ -44,6 +44,7 @@ import org.springframework.context.annotation.Conditional;
 import org.acumos.cds.client.ICommonDataServiceRestClient;
 import org.acumos.cds.domain.MLPPeer;
 import org.acumos.cds.transport.RestPageResponse;
+import org.acumos.cds.transport.RestPageRequest;
 
 /**
  * 
@@ -52,6 +53,8 @@ import org.acumos.cds.transport.RestPageResponse;
 @Service
 public class PeerServiceImpl extends AbstractServiceImpl implements PeerService {
 
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(PeerServiceImpl.class.getName());
+
        /**
         * 
         */
@@ -62,6 +65,7 @@ public class PeerServiceImpl extends AbstractServiceImpl implements PeerService
        public MLPPeer getSelf() {
                RestPageResponse<MLPPeer> response = 
                        getClient().searchPeers(new MapBuilder().put("isSelf", Boolean.TRUE).build(), false, null);
+               log.debug(EELFLoggerDelegate.errorLogger, "Peers representing 'self': " + response.getContent());
                if (response.getSize() != 1) {
                        log.warn(EELFLoggerDelegate.errorLogger, "Number of peers representing 'self' not 1: " + response.getSize());
                        return null;
@@ -75,19 +79,22 @@ public class PeerServiceImpl extends AbstractServiceImpl implements PeerService
        @Override
        public List<MLPPeer> getPeers(ServiceContext theContext) {
                log.debug(EELFLoggerDelegate.debugLogger, "getPeers");
+
+               RestPageRequest pageRequest = new RestPageRequest(0, 100);
+               RestPageResponse<MLPPeer> pageResponse = null;
+               List<MLPPeer> peers = new ArrayList<MLPPeer>(),
+                                                                       pagePeers = null;
                ICommonDataServiceRestClient cdsClient = getClient();
-               List<MLPPeer> mlpPeers = null;
-               /*
-                * cdsClient.searchPeers( new MapBuilder() .put("status", PeerStatus.ACTIVE)
-                * .build(), false);
-                */
-               RestPageResponse<MLPPeer> mlpPeersPage = cdsClient.getPeers(null);
-               if (mlpPeersPage != null)
-                       mlpPeers = mlpPeersPage.getContent();
-               if (mlpPeers != null) {
-                       log.debug(EELFLoggerDelegate.debugLogger, "getPeers size:{}", mlpPeers.size());
+
+               do {
+                       pageResponse = cdsClient.getPeers(pageRequest);
+                       peers.addAll(pageResponse.getContent());
+               
+                       pageRequest.setPage(pageResponse.getNumber() + 1);
                }
-               return mlpPeers;
+               while (!pageResponse.isLast());
+
+               return peers;
        }
 
        @Override
index 1c615a4..5059feb 100644 (file)
@@ -56,8 +56,9 @@ import org.springframework.beans.factory.annotation.Autowired;
 
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.service.PeerService;
-import org.acumos.federation.gateway.service.ServiceContext;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
+import org.acumos.federation.gateway.service.ServiceContext;
+import org.acumos.federation.gateway.service.ServiceException;
 
 import org.acumos.cds.domain.MLPPeer;
 import org.acumos.cds.domain.MLPPeerSubscription;
@@ -68,6 +69,8 @@ import org.apache.commons.io.IOUtils;
 @ConfigurationProperties(prefix = "peersLocal")
 public class PeerServiceLocalImpl extends AbstractServiceLocalImpl implements PeerService, PeerSubscriptionService {
 
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(PeerServiceLocalImpl.class.getName());
+
        private List<FLPPeer> peers;
 
        @PostConstruct
@@ -181,18 +184,18 @@ public class PeerServiceLocalImpl extends AbstractServiceLocalImpl implements Pe
 
        /** */
        @Override
-       public boolean updatePeerSubscription(MLPPeerSubscription theSub) {
+       public void updatePeerSubscription(MLPPeerSubscription theSub) throws ServiceException {
                for (FLPPeer peer : this.peers) {
                        for (int i = 0; i < peer.getSubscriptions().size(); i++) {
                                MLPPeerSubscription peerSub = peer.getSubscriptions().get(i);
                                if (theSub.getSubId().equals(peerSub.getSubId()) &&
                                                theSub.getPeerId().equals(peerSub.getPeerId())) {
                                        peer.getSubscriptions().set(i, theSub);
-                                       return true;
+                                       return;
                                }
                        }
                }
-               return false;
+               throw new ServiceException("No such subscription");
        }
 
        /** */
index aecb62b..50d5341 100644 (file)
@@ -28,7 +28,9 @@ import java.util.stream.Collectors;
 
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
+import org.acumos.federation.gateway.service.ServiceException;
 import org.acumos.federation.gateway.util.Utils;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.env.Environment;
 import org.springframework.stereotype.Service;
@@ -45,6 +47,8 @@ import org.acumos.cds.transport.RestPageResponse;
 @Service
 public class PeerSubscriptionServiceImpl extends AbstractServiceImpl implements PeerSubscriptionService {
 
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(PeerSubscriptionServiceImpl.class.getName());
+
        @Autowired
        private Environment env;
 
@@ -52,58 +56,33 @@ public class PeerSubscriptionServiceImpl extends AbstractServiceImpl implements
         * 
         */
        public PeerSubscriptionServiceImpl() {
-               // TODO Auto-generated constructor stub
        }
 
        @Override
-       public List<MLPPeerSubscription> getPeerSubscriptions(String peerId) {
-               log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscriptions:{}", peerId);
-               List<MLPPeerSubscription> peerSubscriptions = null;
-               // Temporary Fix as COmmon Data Service does not handle proper Serialization
-               peerSubscriptions = getClient().getPeerSubscriptions(peerId);
-               /*
-                * if(!Utils.isEmptyList(mlpPeerSubscriptions)) { //mlpPeerSubscriptions =
-                * mlpPeerSubscriptionPaged.getContent(); mlpPeerSubscriptions =
-                * mlpPeerSubscriptions.stream().filter(mlpPeerSubscription ->
-                * (mlpPeerSubscription.getPeerId().contains(peerId))).collect(Collectors.toList
-                * ()); }
-                */
-               log.debug(EELFLoggerDelegate.debugLogger, "peer {} subscriptions : {}", peerId, peerSubscriptions.size());
+       public List<MLPPeerSubscription> getPeerSubscriptions(String thePeerId) {
+               log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscriptions:{}", thePeerId);
+               List<MLPPeerSubscription> peerSubscriptions = getClient().getPeerSubscriptions(thePeerId);
+               log.debug(EELFLoggerDelegate.debugLogger, "peer {} subscriptions : {}", thePeerId, peerSubscriptions.size());
                return peerSubscriptions;
        }
 
        @Override
-       public MLPPeerSubscription getPeerSubscription(Long subId) {
-               log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscription:{}", subId);
-               ICommonDataServiceRestClient cdsClient = getClient();
-               MLPPeerSubscription existingMLPPeerSubscription = null;
-               existingMLPPeerSubscription = cdsClient.getPeerSubscription(subId);
-               if (existingMLPPeerSubscription != null) {
-                       log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscription :{}",
-                                       existingMLPPeerSubscription.toString());
-               }
-               return existingMLPPeerSubscription;
+       public MLPPeerSubscription getPeerSubscription(Long theSubId) {
+               log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscription:{}", theSubId);
+               MLPPeerSubscription peerSubscription = getClient().getPeerSubscription(theSubId);
+               log.debug(EELFLoggerDelegate.debugLogger, "getPeerSubscription :{}", peerSubscription);
+               return peerSubscription;
        }
 
        @Override
-       public boolean updatePeerSubscription(MLPPeerSubscription mlpPeerSubscription) {
+       public void updatePeerSubscription(MLPPeerSubscription theSubscription) throws ServiceException {
                log.debug(EELFLoggerDelegate.debugLogger, "updatePeerSubscription");
                ICommonDataServiceRestClient cdsClient = getClient();
-               boolean isUpdatedSuccessfully = false;
-               MLPPeerSubscription existingMLPPeerSubscription = null;
-               try {
-                       existingMLPPeerSubscription = getPeerSubscription(mlpPeerSubscription.getSubId());
-                       if (existingMLPPeerSubscription != null) {
-                               if (mlpPeerSubscription.getPeerId().equalsIgnoreCase(existingMLPPeerSubscription.getPeerId()))
-                                       cdsClient.updatePeerSubscription(mlpPeerSubscription);
-                               isUpdatedSuccessfully = true;
-                       }
-               } catch (Exception e) {
-                       isUpdatedSuccessfully = false;
-                       log.error(EELFLoggerDelegate.debugLogger,
-                                       "updatePeer: Exception while deleting the MLPPeerSubscription record:", e);
-               }
-               return isUpdatedSuccessfully;
+               MLPPeerSubscription existingSubscription = cdsClient.getPeerSubscription(theSubscription.getSubId());
+               //this effectively stops one from re-assigning a subscription to another peer.
+               if (!theSubscription.getPeerId().equalsIgnoreCase(existingSubscription.getPeerId()))
+                       throw new ServiceException("Peer id mismatch with existing subscription");
+               cdsClient.updatePeerSubscription(theSubscription);
        }
 
 }
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ServiceImpl.java b/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ServiceImpl.java
new file mode 100644 (file)
index 0000000..245755c
--- /dev/null
@@ -0,0 +1,73 @@
+/*-
+ * ===============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.service.impl;
+
+import java.util.Map;
+import java.util.List;
+
+import org.acumos.federation.gateway.service.ServiceException;
+
+import org.acumos.cds.domain.MLPSolution;
+
+/**
+ * Some basic tooling for service implementation.
+ * Common functionality to be re-used across service implementations.
+ */
+public interface ServiceImpl {
+
+       /**
+        * Bit of a primitive implementation
+        */
+       public static boolean isSelectable(MLPSolution theSolution, Map<String, ?> theSelector) /*throws ServiceException*/ {
+               boolean res = true;
+
+               if (theSelector == null || theSelector.isEmpty())
+                       return true;
+
+               Object modelTypeCode = theSelector.get("modelTypeCode");
+               if (modelTypeCode != null) {
+                       if (modelTypeCode instanceof String) {
+                               res &= theSolution.getModelTypeCode().equals(modelTypeCode);
+                       }
+                       else if (modelTypeCode instanceof List) {
+                               res &= ((List)modelTypeCode).contains(theSolution.getModelTypeCode());
+                       }
+                       else
+                               res = false;
+               }
+
+               Object toolkitTypeCode = theSelector.get("toolkitTypeCode");
+               if (toolkitTypeCode != null) {
+                       if (toolkitTypeCode instanceof String) {
+                               res &= theSolution.getToolkitTypeCode().equals(toolkitTypeCode);
+                       }
+                       else if (toolkitTypeCode instanceof List) {
+                               res &= ((List)toolkitTypeCode).contains(theSolution.getToolkitTypeCode());
+                       }
+                       else
+                               res = false;
+               }
+
+               return res;
+       }
+
+
+}
index 474172b..903f1b5 100644 (file)
@@ -22,6 +22,7 @@ package org.acumos.federation.gateway.task;
 
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 import org.acumos.cds.domain.MLPPeer;
 import org.acumos.cds.domain.MLPPeerSubscription;
@@ -87,17 +88,29 @@ public class PeerSubscriptionTask implements Runnable {
                        return;
                }
 
+               Map selector = Utils.jsonStringToMap(this.subscription.getSelector());
+               Date lastProcessed = this.subscription.getProcessed();
+               if (lastProcessed != null) {
+                       selector.put("modified", lastProcessed);
+               }
+
                try {
                        log.info(EELFLoggerDelegate.debugLogger, "Peer task for peer {}, subscription {}", this.peer.getName(), this.subscription.getSubId());
                        FederationClient fedClient = clients.getFederationClient(this.peer.getApiUrl());
-                       JsonResponse<List<MLPSolution>> response =
-                               fedClient.getSolutions(Utils.jsonStringToMap(this.subscription.getSelector()));
+                       JsonResponse<List<MLPSolution>> response = fedClient.getSolutions(selector);
                        log.info(EELFLoggerDelegate.debugLogger, "Peer task for peer {}, subscription {} got response {}", this.peer.getName(), this.subscription.getSubId(), response);
-                       if (response != null && response.getContent() != null) {
+                       if (response != null) {
                                List<MLPSolution> solutions = response.getContent();
-                               if (solutions.size() > 0) {
-                                       this.eventPublisher.publishEvent(
+                               if (solutions != null) {
+                                       //keep only those updated since last processed
+                                       //this assumes we can trust the last processed to be maintained correctly by the peer .. unreliable
+                                       //solutions = solutions.stream()
+                                       //                                                      .filter(solution -> solution.getLastUpdate().after(this.subscription.getProcessed()))
+                                       //                                                      .collect(Collectors.toList());
+                                       if (solutions.size() > 0) {
+                                               this.eventPublisher.publishEvent(
                                                        new PeerSubscriptionEvent(this, this.peer, this.subscription, solutions));
+                                       }
                                }
                        }
 
index a388593..f7dda8a 100644 (file)
@@ -268,17 +268,35 @@ public class PeerGatewayTest {
                                        any(Map.class), any(Boolean.class), any(RestPageRequest.class)
                                )
                        )
-                       .thenAnswer(new Answer<List<MLPPeer>>() {
-                                       public List<MLPPeer> answer(InvocationOnMock theInvocation) {
+                       .thenAnswer(new Answer<RestPageResponse<MLPPeer>>() {
+                                       public RestPageResponse<MLPPeer> answer(InvocationOnMock theInvocation) {
+                                               Map selector = (Map)theInvocation.getArguments()[0];
                                                MLPPeer peer = new MLPPeer();
-                                               peer.setPeerId("1");
-                                               peer.setName("testPeer");
-                                               peer.setSubjectName("test.org");
-                                               peer.setStatusCode(PeerStatus.Active.code());
-                                               peer.setSelf(false);
-                                               peer.setApiUrl("https://localhost:1111");
-
-                                               return Collections.singletonList(peer);
+                                               if (selector != null && selector.containsKey("isSelf") && selector.get("isSelf").equals(Boolean.TRUE)) {
+                                                       peer.setPeerId("0");
+                                                       peer.setName("testSelf");
+                                                       peer.setSubjectName("test.org");
+                                                       peer.setStatusCode(PeerStatus.Active.code());
+                                                       peer.setSelf(true);
+                                                       peer.setApiUrl("https://localhost:1110");
+                                               }
+                                               else {
+                                                       peer.setPeerId("1");
+                                                       peer.setName("testPeer");
+                                                       peer.setSubjectName("test.org");
+                                                       peer.setStatusCode(PeerStatus.Active.code());
+                                                       peer.setSelf(false);
+                                                       peer.setApiUrl("https://localhost:1111");
+                                               }
+       
+                                               RestPageResponse page = new RestPageResponse(Collections.singletonList(peer));
+                                               page.setNumber(1);
+                                               page.setSize(1);
+                                               page.setTotalPages(1);
+                                               page.setTotalElements(1);
+                                               page.setFirst(true);
+                                               page.setLast(true);
+                                               return page;
                                        }
                                });
                
@@ -288,8 +306,7 @@ public class PeerGatewayTest {
                                )
                        )
                        .thenAnswer(new Answer<RestPageResponse<MLPPeer>>() {
-                                       public RestPageResponse<MLPPeer>
-                                               answer(InvocationOnMock theInvocation) {
+                                       public RestPageResponse<MLPPeer> answer(InvocationOnMock theInvocation) {
                                                MLPPeer peer = new MLPPeer();
                                                peer.setPeerId("1");
                                                peer.setName("testPeer");
@@ -298,7 +315,14 @@ public class PeerGatewayTest {
                                                peer.setSelf(false);
                                                peer.setApiUrl("https://localhost:1111");
 
-                                               return new RestPageResponse(Collections.singletonList(peer));
+                                               RestPageResponse page = new RestPageResponse(Collections.singletonList(peer));
+                                               page.setNumber(1);
+                                               page.setSize(1);
+                                               page.setTotalPages(1);
+                                               page.setTotalElements(1);
+                                               page.setFirst(true);
+                                               page.setLast(true);
+                                               return page;
                                        }
                                });
        
index 843e68a..44e4888 100644 (file)
@@ -38,6 +38,8 @@ import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
 import org.acumos.federation.gateway.common.Clients;
 import org.acumos.federation.gateway.common.FederationClient;
+import org.acumos.federation.gateway.cds.Solution;
+
 import org.springframework.beans.factory.annotation.Autowired;
 //import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.boot.context.properties.ConfigurationProperties;
@@ -132,8 +134,9 @@ public class TestAdapter {
 
                                        List<MLPSolutionRevision> revisions = null;
                                        try {
-                                               revisions = (List<MLPSolutionRevision>) fedClient.getSolutionRevisions(solution.getSolutionId())
-                                                               .getContent();
+                                               Solution sol = (Solution)fedClient.getSolution(solution.getSolutionId()).getContent();
+                                               log.info(EELFLoggerDelegate.debugLogger, "retrieved solution {}", solution);
+                                               revisions = sol.getRevisions();
                                        }
                                        catch (Exception x) {
                                                log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve revisions", x);
index 0025161..ef9636d 100644 (file)
@@ -21,7 +21,7 @@
                        {
         "subId":1,
                                "peerId":"5d2f3b51-3d38-46cd-b171-7e0f3718087a",
-                               "selector":"{\"modelTypeCode\":\"CL,PR\"}",
+                               "selector":"{\"modelTypeCode\":[\"CL\",\"PR\"]}",
                                "refreshInterval":"300",
                                "maxArtifactSize":"2048",
                                "created":"2017-08-12",
index 3c7b861..6b220af 100644 (file)
@@ -24,7 +24,7 @@
      {
       "artifactId":"2a0f28e3-ccd9-40e1-a57c-62a57fb46b76",
       "name":"configuration",
-      "uri":"classpath:application-acumosb.properties",
+      "uri":"file:///home/jora/data/acumos/image",
       "metadata":"acumosb",
          "created":"2017-09-10",
          "modified":"2017-09-11"
index 504f25e..8068555 100644 (file)
@@ -20,7 +20,7 @@
                        {
                                "subId":1,
                                "peerId":"5d2f3b51-3d38-46cd-b171-7e0f3718087a",
-                               "selector":"{\"modelTypeCode\":\"CL,PR\"}",
+                               "selector":"{\"modelTypeCode\":\"CL\"}",
                                "refreshInterval":"120",
                                "maxArtifactSize":"2048",
                                "created":"2017-09-21",
index f43df71..4b1858d 100644 (file)
@@ -21,7 +21,7 @@
                        {
                                "subId":1,
                                "peerId":"11111111-1111-1111-1111-111111111111",
-                               "selector":"{\"modelTypeCode\":\"CL,PR\"}",
+                               "selector":"{\"modelTypeCode\":[\"CL\",\"PR\"]}",
                                "refreshInterval":"120",
                                "maxArtifactSize":"2048",
                                "created":"2017-09-21",