Align with CDS 1.17 38/2538/6
authorSerban Jora <sj2381@att.com>
Tue, 14 Aug 2018 05:00:27 +0000 (01:00 -0400)
committerChris Lott <clott@research.att.com>
Fri, 17 Aug 2018 14:48:20 +0000 (14:48 +0000)
Add document federation.

Issue-ID: ACUMOS-626, ACUMOS-1544, ACUMOS-1606
Change-Id: I47dd1916d8097a324a4220bc9da334254bc99e0b
Signed-off-by: Serban Jora <sj2381@att.com>
30 files changed:
docs/release-notes.rst
gateway/pom.xml
gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java
gateway/src/main/java/org/acumos/federation/gateway/adapter/onap/ONAP.java
gateway/src/main/java/org/acumos/federation/gateway/cds/Document.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/DocumentBuilder.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/cds/Mapper.java
gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevision.java
gateway/src/main/java/org/acumos/federation/gateway/common/API.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/config/AdapterConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/DockerConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/GatewayConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/config/NexusConfiguration.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/controller/CatalogController.java
gateway/src/main/java/org/acumos/federation/gateway/service/ArtifactService.java [deleted file]
gateway/src/main/java/org/acumos/federation/gateway/service/CatalogService.java
gateway/src/main/java/org/acumos/federation/gateway/service/ContentService.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceImpl.java [deleted file]
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/ContentServiceImpl.java [new file with mode: 0644]
gateway/src/main/java/org/acumos/federation/gateway/service/impl/ContentServiceLocalImpl.java [moved from gateway/src/main/java/org/acumos/federation/gateway/service/impl/ArtifactServiceLocalImpl.java with 59% similarity]
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/mockPeerSolutionRevisionDocumentsResponse.json [new file with mode: 0644]
gateway/src/test/resources/mockPeerSolutionRevisionResponse.json [new file with mode: 0644]
gateway/src/test/resources/mockPeerSolutionRevisionsResponse.json
gateway/src/test/resources/mockPeerSolutionsResponse.json

index b725760..25b598e 100644 (file)
@@ -22,6 +22,17 @@ Federated Gateway Release Notes
 
 The Federated Gateway server is available as a Docker image in a Docker registry.
 
+Version 1.17.0, 2018-08-14
+-------------------------
+
+* Align with data model changes from CDS 1.17.x
+* Add revision document federation (ACUMS-1606)
+* Add tag federation (ACUMOS-1544)
+* Fix authorship federation (ACUMOS-626)
+* The federation API for access to artifact and document content access have changed 
+  to /solutions/{solutionId}/revisions/{revisionId}/artifacts/{artifactId}/content 
+  and /solutions/{solutionId}/revisions/{revisionId}/documents/{documentId}/content
+
 Version 1.16.1, 2018-08-08
 -------------------------
 
index 0bfc1fa..c857201 100644 (file)
@@ -24,7 +24,7 @@ limitations under the License.
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.acumos.federation</groupId>
        <artifactId>gateway</artifactId>
-       <version>1.16.1-SNAPSHOT</version>
+       <version>1.17.0-SNAPSHOT</version>
        <name>Federation Gateway</name>
        <description>Federated Acumos Interface for inter-acumos and ONAP communication</description>
 
@@ -69,12 +69,12 @@ limitations under the License.
                <dependency>
                        <groupId>org.acumos.acumos-nexus-client</groupId>
                        <artifactId>acumos-nexus-client</artifactId>
-                       <version>2.2.0</version>
+                       <version>2.2.1</version>
                </dependency>
                <dependency>
                        <groupId>org.acumos.common-dataservice</groupId>
                        <artifactId>cmn-data-svc-client</artifactId>
-                       <version>1.16.1</version>
+                       <version>1.17.1</version>
                </dependency>
                <dependency>
                        <groupId>org.json</groupId>
index 3085a0c..5571d13 100644 (file)
@@ -29,11 +29,16 @@ import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 
 import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.cds.AccessTypeCode;
+import org.acumos.cds.domain.MLPTag;
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPPeer;
 import org.acumos.cds.domain.MLPPeerSubscription;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.cds.domain.MLPRevisionDescription;
+import org.acumos.federation.gateway.cds.Document;
 import org.acumos.federation.gateway.cds.Artifact;
 import org.acumos.federation.gateway.cds.Solution;
 import org.acumos.federation.gateway.cds.SolutionRevision;
@@ -43,7 +48,8 @@ import org.acumos.federation.gateway.common.FederationClient;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.config.GatewayCondition;
 import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
-import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ContentService;
+import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.ServiceException;
 import org.acumos.federation.gateway.util.Errors;
 import org.springframework.beans.factory.BeanInitializationException;
@@ -70,7 +76,9 @@ public class PeerGateway {
        @Autowired
        private Clients clients;
        @Autowired
-       private ArtifactService artifacts;
+       private ContentService content;
+       @Autowired
+       private CatalogService catalog;
 
 
        public PeerGateway() {
@@ -174,6 +182,7 @@ public class PeerGateway {
                                                localSolution = updateMLPSolution(peerSolution, localSolution, cdsClient);
                                        }
 
+                                       addTags(peerSolution, localSolution, cdsClient);
                                        mapSolution(localSolution, cdsClient);
                                }
                                catch (Throwable t) {
@@ -196,7 +205,7 @@ public class PeerGateway {
                                                                                                                                        .withWebStats(null)
                                                                                                                                        .build();
                        try {
-                               cdsClient.createSolution(localSolution);
+                               cdsClient.createSolution(localSolution);        
                                return localSolution;
                        }
                        catch (HttpStatusCodeException restx) {
@@ -266,6 +275,36 @@ public class PeerGateway {
                                                                .build();
                }
 
+               private MLPDocument createMLPDocument(String theSolutionId, String theRevisionId, MLPDocument peerDocument,
+                               ICommonDataServiceRestClient cdsClient) {
+
+                       Document document = Document.buildFrom(peerDocument)
+                                                                                                               .withUser(getUserId(this.sub))
+                                                                                                               .build();
+                       try {
+                               cdsClient.createDocument(document);
+                               cdsClient.addSolutionRevisionDocument(theRevisionId, AccessTypeCode.PB.name(), document.getDocumentId());
+                               return document;
+                       }
+                       catch (HttpStatusCodeException restx) {
+                               log.error(EELFLoggerDelegate.errorLogger,
+                                               "createDocument CDS call failed. CDS message is " + restx.getResponseBodyAsString(), restx);
+                               return null;
+                       }
+                       catch (Exception x) {
+                               log.error(EELFLoggerDelegate.errorLogger, "createDocument unexpected failure", x);
+                               return null;
+                       }
+               }
+
+               private MLPDocument copyMLPDocument(MLPDocument peerDocument, MLPDocument localDocument) {
+
+                       return Document.buildFrom(peerDocument)
+                                                               .withId(localDocument.getDocumentId())
+                                                               .withUser(getUserId(this.sub))
+                                                               .build();
+               }
+
                private MLPSolution updateMLPSolution(final MLPSolution peerSolution, final MLPSolution localSolution,
                                ICommonDataServiceRestClient cdsClient) {
                        log.info(EELFLoggerDelegate.debugLogger,
@@ -321,6 +360,17 @@ public class PeerGateway {
                        }
                }
 
+               private void addTags(MLPSolution peerSolution, MLPSolution localSolution, ICommonDataServiceRestClient cdsClient) {
+                       for (MLPTag tag: peerSolution.getTags()) {
+                               try {
+                                       cdsClient.addSolutionTag(localSolution.getSolutionId(), tag.getTag());
+                               }
+                               catch (HttpStatusCodeException restx) {
+                                       //we ignore and keep trying
+                               }
+                       }
+               }
+       
                /**
                 * Here comes the core process of updating a local solution's related
                 * information with what is available from a peer.
@@ -352,26 +402,21 @@ public class PeerGateway {
                        // this should not happen as any solution should have at least one
                        // revision (but that's an assumption on how on-boarding works)
                        if (peerRevisions == null || peerRevisions.size() == 0) {
-                               log.warn(EELFLoggerDelegate.debugLogger, "No revisions were retrieved");
+                               log.warn(EELFLoggerDelegate.debugLogger, "No peer revisions were retrieved");
                                return;
                        }
 
                        // check if we have locally the latest revision available on the peer
-                       // TODO: this is just one possible policy regarding the handling of
-                       // such a mismatch
-                       List<MLPSolutionRevision> cdsRevisions = Collections.EMPTY_LIST;
+                       List<MLPSolutionRevision> catalogRevisions = Collections.EMPTY_LIST;
                        try {
-                               cdsRevisions = cdsClient.getSolutionRevisions(theSolution.getSolutionId());
+                               catalogRevisions = catalog.getSolutionRevisions(theSolution.getSolutionId());
                        }
-                       catch (HttpStatusCodeException restx) {
-                               if (!Errors.isCDSNotFound(restx)) {
-                                       log.error(EELFLoggerDelegate.errorLogger,
-                                                       "getSolutionRevisions CDS call failed. CDS message is " + restx.getResponseBodyAsString(),
-                                                       restx);
-                                       throw restx;
-                               }
+                       catch (ServiceException sx) {
+                               log.error(EELFLoggerDelegate.errorLogger,
+                                                       "Failed to retrieve catalog revisions for solution " + theSolution.getSolutionId(), sx);
+                               throw sx;
                        }
-                       final List<MLPSolutionRevision> localRevisions = cdsRevisions;
+                       final List<MLPSolutionRevision> localRevisions = catalogRevisions;
 
                        // map peer revisions to local ones; new peer revisions have a null mapping
                        Map<MLPSolutionRevision, MLPSolutionRevision> peerToLocalRevisions =
@@ -387,18 +432,24 @@ public class PeerGateway {
 
                        for (Map.Entry<MLPSolutionRevision, MLPSolutionRevision> revisionEntry : peerToLocalRevisions.entrySet()) {
                                MLPSolutionRevision peerRevision = revisionEntry.getKey(), localRevision = revisionEntry.getValue();
-                               // get peer artifacts
-                               List<MLPArtifact> peerArtifacts = null;
+                       
+                               //revision related information (artifacts/documents/description/..) is now embedded in the revision details
+                               //federation api call so one call is all is needed      
                                try {
-                                       peerArtifacts = (List<MLPArtifact>) fedClient
-                                                       .getArtifacts(theSolution.getSolutionId(), peerRevision.getRevisionId()).getContent();
+                                       peerRevision = fedClient.getSolutionRevision(theSolution.getSolutionId(), peerRevision.getRevisionId())
+                                                                                                                                               .getContent();
                                }
                                catch (Exception x) {
-                                       log.warn(EELFLoggerDelegate.errorLogger, "Failed to retrieve peer acumos artifacts", x);
+                                       log.warn(EELFLoggerDelegate.errorLogger, "Failed to retrieve peer acumos artifact details", x);
                                        throw x;
                                }
 
-                               List<MLPArtifact> cdsArtifacts = Collections.EMPTY_LIST;
+                               List<MLPArtifact> peerArtifacts = (List)((SolutionRevision)peerRevision).getArtifacts();
+                               List<MLPDocument> peerDocuments = (List)((SolutionRevision)peerRevision).getDocuments();
+
+                               List<MLPArtifact> catalogArtifacts = Collections.EMPTY_LIST;
+                               List<MLPDocument>       catalogDocuments = Collections.EMPTY_LIST;
+                               
                                if (localRevision == null) {
                                        localRevision = createMLPSolutionRevision(peerRevision, cdsClient);
                                        if (localRevision == null) {
@@ -408,20 +459,20 @@ public class PeerGateway {
                                }
                                else {
                                        try {
-                                               cdsArtifacts = cdsClient.getSolutionRevisionArtifacts(theSolution.getSolutionId(),
-                                                               localRevision.getRevisionId());
+                                               localRevision = catalog.getSolutionRevision(
+                                                                                                                               theSolution.getSolutionId(), localRevision.getRevisionId());
                                        }
-                                       catch (HttpStatusCodeException restx) {
-                                               if (!Errors.isCDSNotFound(restx)) {
-                                                       log.error(EELFLoggerDelegate.errorLogger,
-                                                                       "getArtifact CDS call failed. CDS message is " + restx.getResponseBodyAsString(),
-                                                                       restx);
-                                                       throw restx;
-                                               }
+                                       catch (ServiceException sx) {
+                                               log.error(EELFLoggerDelegate.errorLogger,
+                                                               "Failed to retrieve catalog solution revision details for  " + theSolution.getSolutionId() + "/" + localRevision.getRevisionId(), sx);
+                                               throw sx;
                                        }
+
+                                       catalogArtifacts = (List)((SolutionRevision)localRevision).getArtifacts();
+                                       catalogDocuments = (List)((SolutionRevision)localRevision).getDocuments();
                                }
 
-                               final List<MLPArtifact> localArtifacts = cdsArtifacts;
+                               final List<MLPArtifact> localArtifacts = catalogArtifacts;
                                // map the artifacts
                                // TODO: track deleted artifacts
                                Map<MLPArtifact, MLPArtifact> peerToLocalArtifacts = new HashMap<MLPArtifact, MLPArtifact>();
@@ -454,7 +505,8 @@ public class PeerGateway {
                                                // data is a more flexible approach.
                                                Resource artifactContent = null;
                                                try {
-                                                       artifactContent = fedClient.downloadArtifact(peerArtifact.getArtifactId());
+                                                       artifactContent = fedClient.getArtifactContent(
+                                                               theSolution.getSolutionId(), localRevision.getRevisionId(), peerArtifact.getArtifactId());
                                                        log.info(EELFLoggerDelegate.debugLogger, "Received {} bytes of artifact content", artifactContent.contentLength()); 
                                                }
                                                catch (Exception x) {
@@ -463,7 +515,8 @@ public class PeerGateway {
 
                                                if (artifactContent != null) {
                                                        try {
-                                                               artifacts.putArtifactContent(localArtifact, artifactContent);
+                                                               content.putArtifactContent(
+                                                                       theSolution.getSolutionId(), localRevision.getRevisionId(), localArtifact, artifactContent);
                                                                doUpdate = true;
                                                        }
                                                        catch (ServiceException sx) {
@@ -484,6 +537,99 @@ public class PeerGateway {
                                                                        restx);
                                                }
                                        }
+                               } //end map artifacts loop
+
+
+                               final List<MLPDocument> localDocuments = catalogDocuments;
+                               // map the documents
+                               // TODO: track deleted documents
+                               Map<MLPDocument, MLPDocument> peerToLocalDocuments = new HashMap<MLPDocument, MLPDocument>();
+                               peerDocuments.forEach(peerDocument -> peerToLocalDocuments.put(peerDocument, localDocuments.stream()
+                                               .filter(localDocument -> localDocument.getDocumentId().equals(peerDocument.getDocumentId()))
+                                               .findFirst().orElse(null)));
+
+                               for (Map.Entry<MLPDocument, MLPDocument> documentEntry : peerToLocalDocuments.entrySet()) {
+                                       MLPDocument peerDocument = documentEntry.getKey(),
+                                                                                       localDocument = documentEntry.getValue();
+                                       boolean doUpdate = false;
+
+                                       if (localDocument == null) {
+                                               localDocument = createMLPDocument(theSolution.getSolutionId(), localRevision.getRevisionId(),
+                                                               peerDocument, cdsClient);
+                                       }
+                                       else {
+                                               //what if the local document has been modified past the last fetch ??
+                                               if (!peerDocument.getVersion().equals(localDocument.getVersion())) {
+                                                       // update local doc
+                                                       localDocument = copyMLPDocument(peerDocument, localDocument);
+                                                       doUpdate = true;
+                                               }
+                                       }
+
+                                       boolean doContent = (peerDocument.getUri() != null) &&
+                                                                                                                       (SubscriptionScope.Full == SubscriptionScope.forCode(this.sub.getScopeType()));
+                                       if (doContent) {
+                                               log.info(EELFLoggerDelegate.debugLogger, "Processing content for document {}", peerDocument); 
+                                               // TODO: we are trying to access the document by its identifier which
+                                               // is fine in the common case but the uri specified in the document
+                                               // data is a more flexible approach.
+                                               Resource documentContent = null;
+                                               try {
+                                                       documentContent = fedClient.getDocumentContent(
+                                                               theSolution.getSolutionId(), localRevision.getRevisionId(), peerDocument.getDocumentId());
+                                                       log.info(EELFLoggerDelegate.debugLogger, "Received {} bytes of document content", documentContent.contentLength()); 
+                                               }
+                                               catch (Exception x) {
+                                                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve acumos document content", x);
+                                               }
+
+                                               if (documentContent != null) {
+                                                       try {
+                                                               content.putDocumentContent(
+                                                                       theSolution.getSolutionId(), localRevision.getRevisionId(), localDocument, documentContent);
+                                                               doUpdate = true;
+                                                       }
+                                                       catch (ServiceException sx) {
+                                                               log.error(EELFLoggerDelegate.errorLogger,
+                                                                                       "Failed to store document content to local repo", sx);
+                                                       }
+                                               }
+                                       }
+
+                                       if (doUpdate) {
+                                               try {
+                                                       cdsClient.updateDocument(localDocument);
+                                                       log.info(EELFLoggerDelegate.debugLogger, "Local document updated with local content reference: {}", localDocument); 
+                                               }
+                                               catch (HttpStatusCodeException restx) {
+                                                       log.error(EELFLoggerDelegate.errorLogger,
+                                                                       "updateDocument CDS call failed. CDS message is " + restx.getResponseBodyAsString(),
+                                                                       restx);
+                                               }
+                                       }
+       
+                               } // end map documents loop
+                               
+                               MLPRevisionDescription catalogDescription = ((SolutionRevision)localRevision).getRevisionDescription();
+                               MLPRevisionDescription peerDescription = ((SolutionRevision)peerRevision).getRevisionDescription();
+
+                               if (peerDescription != null) {
+                                       try {
+                                               if (catalogDescription == null) {
+                                                       cdsClient.createRevisionDescription(peerDescription);
+                                               }
+                                               else {
+                                                       //is this a good enough test ??
+                                                       if (peerDescription.getModified().after(catalogDescription.getModified())) {
+                                                               cdsClient.updateRevisionDescription(peerDescription);
+                                                       }
+                                               }
+                                       }
+                                       catch (HttpStatusCodeException restx) {
+                                               log.error(EELFLoggerDelegate.errorLogger,
+                                                                       "Failed to store revision description. CDS message is " + restx.getResponseBodyAsString(),
+                                               restx);
+                                       }
                                }
                        }
                } // mapSolution
index 356c5aa..35fa9aa 100644 (file)
@@ -275,7 +275,7 @@ public class ONAP {
 
                        //we could have a new model, a new model revision or updates to the currently mapped revision's artifacts.
                        //currently we always fast-forward to the latest revision available in acumos
-                       MLPSolutionRevision mappedAcumosRevision = mappedAcumosRevision = theRevisions.get(theRevisions.size() - 1);
+                       MLPSolutionRevision mappedAcumosRevision = theRevisions.get(theRevisions.size() - 1);
 
                        List<MLPArtifact> acumosArtifacts = null;
                        try {
@@ -341,7 +341,9 @@ public class ONAP {
                        log.info(EELFLoggerDelegate.debugLogger, "New artifacts: " + newArtifacts);
                        for (MLPArtifact acumosArtifact : newArtifacts) {
                                try {
-                                       for (ASDC.ArtifactUploadAction uploadAction:  mapNewArtifact(theAssetInfo, acumosArtifact)) {
+                                       for (ASDC.ArtifactUploadAction uploadAction:
+                                                               mapNewArtifact(theAssetInfo, theSolution.getSolutionId(), mappedAcumosRevision.getRevisionId(),
+                                                                                                                        acumosArtifact)) {
                                                uploadAction.execute().waitForResult();
                                        }
                                }
@@ -354,7 +356,9 @@ public class ONAP {
                        for (Map.Entry<MLPArtifact, JSONArray> updateEntry : updatedArtifacts.entrySet()) {
                                MLPArtifact acumosArtifact = updateEntry.getKey();
                                try {
-                                       for (ASDC.ArtifactUpdateAction updateAction:  mapArtifact(theAssetInfo, updateEntry.getKey(), updateEntry.getValue())) {
+                                       for (ASDC.ArtifactUpdateAction updateAction: 
+                                                               mapArtifact(theAssetInfo, theSolution.getSolutionId(), mappedAcumosRevision.getRevisionId(),
+                                                                                                               updateEntry.getKey(), updateEntry.getValue())) {
                                                updateAction.execute().waitForResult();
                                        }
                                }
@@ -395,13 +399,15 @@ public class ONAP {
 
                /**
                 */
-               private List<ASDC.ArtifactUploadAction> mapNewArtifact(JSONObject theSDCAsset, MLPArtifact theAcumosArtifact) {
+               private List<ASDC.ArtifactUploadAction> mapNewArtifact(
+                       JSONObject theSDCAsset,
+                       String theAcumosSolutionId, String theAcumosRevisionId, MLPArtifact theAcumosArtifact) {
 
                        if (isDCAEComponentSpecification(theAcumosArtifact)) {
 
                                byte[] content = null;
                                try {
-                                       content = retrieveContent(theAcumosArtifact);
+                                       content = retrieveContent(theAcumosSolutionId, theAcumosRevisionId, theAcumosArtifact);
                                }
                                catch (Exception x) {
                                        log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve Acumoms artifact content from " + theAcumosArtifact.getUri(), x);
@@ -456,12 +462,14 @@ public class ONAP {
                        }
                }
                
-               private List<ASDC.ArtifactUpdateAction> mapArtifact(JSONObject theSDCAsset, MLPArtifact theAcumosArtifact, JSONArray theSDCArtifacts) {
+               private List<ASDC.ArtifactUpdateAction> mapArtifact(
+                       JSONObject theSDCAsset, String theAcumosSolutionId, String theAcumosRevisionId,
+                       MLPArtifact theAcumosArtifact, JSONArray theSDCArtifacts) {
                        
                        if (isDCAEComponentSpecification(theAcumosArtifact)) {
                                byte[] content = null;
                                try {
-                                       content = retrieveContent(theAcumosArtifact);
+                                       content = retrieveContent(theAcumosSolutionId, theAcumosRevisionId, theAcumosArtifact);
                                }
                                catch (Exception x) {
                                        log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve Acumoms artifact content from " + theAcumosArtifact.getUri(), x);
@@ -550,15 +558,18 @@ public class ONAP {
                        return isAcumos;
                }
 
-               private byte[] retrieveContent(MLPArtifact theAcumosArtifact) throws Exception {
-
+               private byte[] retrieveContent(
+                       String theAcumosSolutionId, String theAcumosRevisionId, MLPArtifact theAcumosArtifact)
+                                                                                                                                                                                                                                                                                                                                                       throws Exception {
                        if (this.peer.isLocal()) {
                                return clients.getNexusClient().getArtifact(theAcumosArtifact.getUri()).toByteArray();
                        }
                        else { //non-local peer
                                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                                StreamUtils.copy(
-                                       clients.getFederationClient(this.peer.getApiUrl()).downloadArtifact(theAcumosArtifact.getArtifactId()).getInputStream(),
+                                       clients.getFederationClient(this.peer.getApiUrl())
+                                               .getArtifactContent(theAcumosSolutionId, theAcumosRevisionId, theAcumosArtifact.getArtifactId())
+                                                       .getInputStream(),
                                        bos);
                                return bos.toByteArray();
                        }
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/Document.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/Document.java
new file mode 100644 (file)
index 0000000..f8c6c78
--- /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.MLPDocument;
+
+/**
+ */
+public class Document extends MLPDocument {
+
+       public Document() {
+       }
+
+       public Document(MLPDocument theCDSDocument) {
+               super(theCDSDocument);
+       }
+       
+       public Document(Document theDocument) {
+               super(theDocument);
+       }
+
+       public static DocumentBuilder build() {
+               return new DocumentBuilder(new Document());
+       }
+
+       public static DocumentBuilder buildFrom(MLPDocument theDocument) {
+               return new DocumentBuilder(new Document(theDocument));
+       }
+
+}
+
+
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/cds/DocumentBuilder.java b/gateway/src/main/java/org/acumos/federation/gateway/cds/DocumentBuilder.java
new file mode 100644 (file)
index 0000000..6c01c7f
--- /dev/null
@@ -0,0 +1,80 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ===============LICENSE_END=========================================================
+ */
+package org.acumos.federation.gateway.cds;
+
+import java.util.Date;
+
+/**
+ */
+public class DocumentBuilder {
+
+       private Document document;
+
+       protected DocumentBuilder(Document theDocument) {
+               this.document = theDocument;
+       }
+
+       public Document build() {
+               return this.document;
+       } 
+
+       public DocumentBuilder withCreatedDate(Date theDate) {
+               this.document.setCreated(theDate);
+               return this;
+       }
+
+       public DocumentBuilder withModifiedDate(Date theDate) {
+               this.document.setModified(theDate);
+               return this;
+       }
+
+       public DocumentBuilder withId(String theDocumentId) {
+               this.document.setDocumentId(theDocumentId);
+               return this;
+       }
+
+       public DocumentBuilder withUser(String theUserId) {
+               this.document.setUserId(theUserId);
+               return this;
+       }
+
+       public DocumentBuilder withVersion(String theVersion) {
+               this.document.setVersion(theVersion);
+               return this;
+       }
+
+       public DocumentBuilder withName(String theName) {
+               this.document.setName(theName);
+               return this;
+       }
+
+       public DocumentBuilder withUri(String theUri) {
+               this.document.setUri(theUri);
+               return this;
+       }
+       
+       public DocumentBuilder withSize(Integer theSize) {
+               this.document.setSize(theSize);
+               return this;
+       }
+
+}
+
+
index 70da464..cfa23d3 100644 (file)
@@ -21,6 +21,7 @@ package org.acumos.federation.gateway.cds;
 
 import java.io.IOException;
 
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
@@ -46,13 +47,13 @@ public class Mapper {
 
                SimpleModule fedModule =
       new SimpleModule("CDSModule",
-          new Version(1, 0, 0, null));
+          new Version(1, 17, 0, null));
     fedModule.addDeserializer(MLPSolution.class, new SolutionDeserializer());
     fedModule.addDeserializer(MLPSolutionRevision.class, new SolutionRevisionDeserializer());
     fedModule.addDeserializer(MLPArtifact.class, new ArtifactDeserializer());
+    fedModule.addDeserializer(MLPDocument.class, new DocumentDeserializer());
                mapper.registerModule(fedModule);
 
-
                return mapper;
        }
        
@@ -98,6 +99,20 @@ public class Mapper {
        }
        }
 
+       private static class DocumentDeserializer extends StdDeserializer<MLPDocument> {
+               public DocumentDeserializer() {
+                       super(MLPDocument.class);
+               }
+               @Override
+       public MLPDocument deserialize(JsonParser theParser, DeserializationContext theCtx) 
+                                                                                                                                                                                               throws IOException, JsonProcessingException {
+         ObjectMapper mapper = (ObjectMapper) theParser.getCodec();
+       return mapper.readValue(theParser, Document.class);
+       }
+       }
+
 
 }
 
index 09eceeb..9cd557e 100644 (file)
@@ -22,10 +22,12 @@ package org.acumos.federation.gateway.cds;
 import java.util.List;
 
 import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPDocument;
+import org.acumos.cds.domain.MLPRevisionDescription;
 import org.acumos.cds.domain.MLPSolutionRevision;
 
 /**
- * Supplements the CDS representation of a solution with related information: revisions.
+ * Supplements the CDS representation of a solution revision with related information: artifacts and (public) documents.
  * Allows federation to pack information passed between peers.
  */
 public class SolutionRevision extends MLPSolutionRevision {
@@ -36,6 +38,8 @@ public class SolutionRevision extends MLPSolutionRevision {
        };
 
        private List<? extends MLPArtifact>             artifacts;
+       private List<? extends MLPDocument>             documents;
+       private MLPRevisionDescription                          description;
 
        public SolutionRevision() {
        }
@@ -52,6 +56,22 @@ public class SolutionRevision extends MLPSolutionRevision {
                return this.artifacts;
        }
 
+       public void setDocuments(List<? extends MLPDocument> theDocuments) {
+               this.documents = theDocuments;
+       }
+
+       public List<? extends MLPDocument>      getDocuments() {
+               return this.documents;
+       }
+
+       public void setRevisionDescription(MLPRevisionDescription theDescription) {
+               this.description = theDescription;      
+       }
+
+       public MLPRevisionDescription getRevisionDescription() {
+               return this.description;
+       }
+
        public static SolutionRevisionBuilder build() {
                return new SolutionRevisionBuilder(new SolutionRevision());
        }
index 39f52bd..b274229 100644 (file)
@@ -37,7 +37,10 @@ public enum API {
        SOLUTION_REVISION_DETAILS(Paths.SOLUTION_REVISION_DETAILS),
        SOLUTION_REVISION_ARTIFACTS(Paths.SOLUTION_REVISION_ARTIFACTS),
        ARTIFACT_DETAILS(Paths.ARTIFACT_DETAILS),
-       ARTIFACT_DOWNLOAD(Paths.ARTIFACT_DOWNLOAD),
+       ARTIFACT_CONTENT(Paths.ARTIFACT_CONTENT),
+       SOLUTION_REVISION_DOCUMENTS(Paths.SOLUTION_REVISION_DOCUMENTS),
+       DOCUMENT_DETAILS(Paths.DOCUMENT_DETAILS),
+       DOCUMENT_CONTENT(Paths.DOCUMENT_CONTENT),
        PEERS(Paths.PEERS),
        SUBSCRIPTION(Paths.SUBSCRIPTION),
        PING(Paths.PING),
@@ -155,8 +158,12 @@ public enum API {
                public static final String SOLUTION_REVISION_DETAILS = "/solutions/{solutionId}/revisions/{revisionId}";
 
                public static final String SOLUTION_REVISION_ARTIFACTS = "/solutions/{solutionId}/revisions/{revisionId}/artifacts";
-               public static final String ARTIFACT_DETAILS = "/artifacts/{artifactId}";
-               public static final String ARTIFACT_DOWNLOAD = "/artifacts/{artifactId}/download";
+               public static final String ARTIFACT_DETAILS = "/solutions/{solutionId}/revisions/{revisionId}/artifacts/{artifactId}";
+               public static final String ARTIFACT_CONTENT = "/solutions/{solutionId}/revisions/{revisionId}/artifacts/{artifactId}/content";
+
+               public static final String SOLUTION_REVISION_DOCUMENTS = "/solutions/{solutionId}/revisions/{revisionId}/documents";
+               public static final String DOCUMENT_DETAILS = "/solutions/{solutionId}/revisions/{revisionId}/documents/{documentId}";
+               public static final String DOCUMENT_CONTENT = "/solutions/{solutionId}/revisions/{revisionId}/documents/{documentId}/content";
 
                public static final String SUBSCRIPTION = "/subscription/{subscriptionId}";
 
index 6631ae7..603670b 100644 (file)
@@ -25,6 +25,7 @@ import java.lang.invoke.MethodHandles;
 import org.acumos.cds.client.CommonDataServiceRestClientImpl;
 import org.acumos.cds.client.ICommonDataServiceRestClient;
 import org.acumos.federation.gateway.cds.Mapper;
+import org.acumos.federation.gateway.config.NexusConfiguration;
 import org.acumos.federation.gateway.config.DockerConfiguration;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
 import org.acumos.federation.gateway.config.FederationInterfaceConfiguration;
@@ -60,6 +61,8 @@ public class Clients {
        private FederationInterfaceConfiguration federationConfig = null;
        @Autowired
        private DockerConfiguration dockerConfig = null;
+       @Autowired
+       private NexusConfiguration nexusConfig = null;
 
        private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -97,21 +100,7 @@ public class Clients {
 
        /** */
        public NexusArtifactClient getNexusClient() {
-               RepositoryLocation repositoryLocation = new RepositoryLocation();
-
-               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);
+               return new NexusArtifactClient(nexusConfig.getRepositoryLocation());
        }
 
        /** */
@@ -121,8 +110,4 @@ public class Clients {
                        .build();
        }
 
-       /** */
-       public Object getDockerProperty(String theName) {
-               return env.getProperty("docker." + theName);
-       }
 }
index 5dad968..ad3ff11 100644 (file)
@@ -27,6 +27,7 @@ import java.util.List;
 import java.util.Map;
 
 import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPPeer;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
@@ -223,6 +224,39 @@ public class FederationClient extends AbstractClient {
                return response == null ? null : response.getBody();
        }
 
+       /**
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
+        * @return Detailed artifact information from Remote Acumos. The returned value can be safely cast to ..gateway.cds.SolutionRevision.
+        * @throws HttpStatusCodeException
+        *             Throws HttpStatusCodeException is remote acumos is not available
+        */
+       public JsonResponse<MLPSolutionRevision> getSolutionRevision(String theSolutionId, String theRevisionId)
+                       throws HttpStatusCodeException {
+
+               URI uri = API.SOLUTION_REVISION_DETAILS.buildUri(this.baseUrl, theSolutionId, theRevisionId);
+               log.info(EELFLoggerDelegate.debugLogger, "Query for " + uri);
+               ResponseEntity<JsonResponse<MLPSolutionRevision>> response = null;
+               try {
+                       response = restTemplate.exchange(uri, HttpMethod.GET, null,
+                                       new ParameterizedTypeReference<JsonResponse<MLPSolutionRevision>>() {
+                                       });
+               }
+               catch (HttpStatusCodeException x) {
+                       log.error(EELFLoggerDelegate.errorLogger, uri + " failed", x);
+                       throw x;
+               }
+               catch (Throwable t) {
+                       log.info(EELFLoggerDelegate.errorLogger, uri + " unexpected failure.", t);
+               }
+               finally {
+                       log.info(EELFLoggerDelegate.debugLogger, uri + " response " + response);
+               }
+               return response == null ? null : response.getBody();
+       }
+
        /**
         * 
         * @param theSolutionId
@@ -257,18 +291,40 @@ public class FederationClient extends AbstractClient {
        }
 
        /**
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
         * @param theArtifactId
         *            Artifact ID
         * @return Resource
         * @throws HttpStatusCodeException
         *             On failure
         */
-       public Resource downloadArtifact(String theArtifactId) throws HttpStatusCodeException {
-               URI uri = API.ARTIFACT_DOWNLOAD.buildUri(this.baseUrl, theArtifactId);
+       public Resource getArtifactContent(String theSolutionId, String theRevisionId, String theArtifactId)
+                                                                                                                                                                                                                                                                                                                                                       throws HttpStatusCodeException {
+               return download(API.ARTIFACT_CONTENT.buildUri(this.baseUrl, theSolutionId, theRevisionId, theArtifactId));
+       }
+
+       /**
+        * 
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
+        * @return List of MLPDocuments from Remote Acumos
+        * @throws HttpStatusCodeException
+        *             Throws HttpStatusCodeException is remote acumos is not available
+        */
+       public JsonResponse<List<MLPDocument>> getDocuments(String theSolutionId, String theRevisionId)
+                       throws HttpStatusCodeException {
+               URI uri = API.SOLUTION_REVISION_DOCUMENTS.buildUri(this.baseUrl, theSolutionId, theRevisionId);
                log.info(EELFLoggerDelegate.debugLogger, "Query for " + uri);
-               ResponseEntity<Resource> response = null;
+               ResponseEntity<JsonResponse<List<MLPDocument>>> response = null;
                try {
-                       response = restTemplate.exchange(uri, HttpMethod.GET, null, Resource.class);
+                       response = restTemplate.exchange(uri, HttpMethod.GET, null,
+                                       new ParameterizedTypeReference<JsonResponse<List<MLPDocument>>>() {
+                                       });
                }
                catch (HttpStatusCodeException x) {
                        log.error(EELFLoggerDelegate.errorLogger, uri + " failed", x);
@@ -276,12 +332,47 @@ public class FederationClient extends AbstractClient {
                }
                catch (Throwable t) {
                        log.error(EELFLoggerDelegate.errorLogger, uri + " unexpected failure.", t);
-                       //not very clean
-                       throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, uri + " unexpected failure: " + t);
                }
                finally {
                        log.info(EELFLoggerDelegate.debugLogger, uri + " response " + response);
                }
+               return response == null ? null : response.getBody();
+       }
+
+       /**
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
+        * @param theDocumentId
+        *            Document ID
+        * @return Resource
+        * @throws HttpStatusCodeException
+        *             On failure
+        */
+       public Resource getDocumentContent(String theSolutionId, String theRevisionId, String theDocumentId)
+                                                                                                                                                                                                                                                                                                                                               throws HttpStatusCodeException {
+               return download(API.DOCUMENT_CONTENT.buildUri(this.baseUrl, theSolutionId, theRevisionId, theDocumentId));
+       }
+
+       protected Resource download(URI theUri) throws HttpStatusCodeException {
+               log.info(EELFLoggerDelegate.debugLogger, "Query for {}", theUri);
+               ResponseEntity<Resource> response = null;
+               try {
+                       response = restTemplate.exchange(theUri, HttpMethod.GET, null, Resource.class);
+               }
+               catch (HttpStatusCodeException x) {
+                       log.error(EELFLoggerDelegate.errorLogger, theUri + " failed", x);
+                       throw x;
+               }
+               catch (Throwable t) {
+                       log.error(EELFLoggerDelegate.errorLogger, theUri + " unexpected failure.", t);
+                       //not very clean
+                       throw new HttpClientErrorException(HttpStatus.BAD_REQUEST, theUri + " unexpected failure: " + t);
+               }
+               finally {
+                       log.info(EELFLoggerDelegate.debugLogger, theUri + " response " + response);
+               }
 
                if (response == null) {
                        //should never get here         
index 1466aef..ffbe836 100644 (file)
@@ -22,12 +22,12 @@ package org.acumos.federation.gateway.config;
 
 import org.acumos.federation.gateway.common.Clients;
 import org.acumos.federation.gateway.security.AuthenticationConfiguration;
-import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ContentService;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.LocalWatchService;
 import org.acumos.federation.gateway.service.PeerService;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
-import org.acumos.federation.gateway.service.impl.ArtifactServiceLocalImpl;
+import org.acumos.federation.gateway.service.impl.ContentServiceLocalImpl;
 import org.acumos.federation.gateway.service.impl.CatalogServiceLocalImpl;
 import org.acumos.federation.gateway.service.impl.PeerServiceLocalImpl;
 import org.acumos.federation.gateway.task.TaskConfiguration;
@@ -48,7 +48,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
                                 AuthenticationConfiguration.class})
 @EnableConfigurationProperties({FederationInterfaceConfiguration.class,
                                                                                                                                LocalInterfaceConfiguration.class,
-                                                                                                                               DockerConfiguration.class})
+                                                                                                                               DockerConfiguration.class,
+                                                                                                                               NexusConfiguration.class})
 @Conditional({AdapterCondition.class})
 @EnableScheduling
 public abstract class AdapterConfiguration  {
@@ -71,8 +72,8 @@ public abstract class AdapterConfiguration  {
        }
 
        @Bean
-       public ArtifactService localArtifactService() {
-               return new ArtifactServiceLocalImpl();
+       public ContentService localContentService() {
+               return new ContentServiceLocalImpl();
        }
 
   @Bean
index 54d574a..8ba7f0d 100644 (file)
@@ -37,49 +37,57 @@ public class DockerConfiguration {
 
        private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
        private DefaultDockerClientConfig.Builder builder;
-
+       // need to repeat as the builder does not expose it and it avoids building a config object every time ..
+       private String registryUrl;
        public DockerConfiguration() {
                reset();
        }
 
        private void reset() {
                this.builder = DefaultDockerClientConfig.createDefaultConfigBuilder();
+               this.registryUrl = null;
        }
 
        public void setHost(String theHost) {
-               builder.withDockerHost(theHost);
+               this.builder.withDockerHost(theHost);
        }
 
        public void setApiVersion(String theVersion) {
-               builder.withApiVersion(theVersion);
+               this.builder.withApiVersion(theVersion);
   }
 
        public void setRegistryUsername(String theUsername) {
-               builder.withRegistryUsername(theUsername);
+               this.builder.withRegistryUsername(theUsername);
        }
 
        public void setRegistryPassword(String thePassword) {
-               builder.withRegistryPassword(thePassword);
+               this.builder.withRegistryPassword(thePassword);
        }
 
        public void setRegistryEmail(String theEmail) {
-               builder.withRegistryEmail(theEmail);
+               this.builder.withRegistryEmail(theEmail);
        }
 
        public void setRegistryUrl(String theUrl) {
-               builder.withRegistryUrl(theUrl);
+               this.registryUrl = theUrl;
+               this.builder.withRegistryUrl(theUrl);
+       }
+       
+       public String getRegistryUrl() {
+               return this.registryUrl;
        }
 
        public void setDockerCertPath(String thePath) {
-               builder.withDockerCertPath(thePath);
+               this.builder.withDockerCertPath(thePath);
        }
 
        public void setDockerConfig(String theConfig) {
-               builder.withDockerConfig(theConfig);
+               this.builder.withDockerConfig(theConfig);
        }
 
        public void setDockerTlsVerify(Boolean doVerify) {
-               builder.withDockerTlsVerify(doVerify);
+               this.builder.withDockerTlsVerify(doVerify);
   }
 
        /*
index 7369c58..ec70073 100644 (file)
@@ -23,12 +23,12 @@ package org.acumos.federation.gateway.config;
 import org.acumos.federation.gateway.adapter.PeerGateway;
 import org.acumos.federation.gateway.common.Clients;
 import org.acumos.federation.gateway.security.AuthenticationConfiguration;
-import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ContentService;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.PeerService;
 import org.acumos.federation.gateway.service.PeerSubscriptionService;
-import org.acumos.federation.gateway.service.impl.ArtifactServiceImpl;
-import org.acumos.federation.gateway.service.impl.ArtifactServiceLocalImpl;
+import org.acumos.federation.gateway.service.impl.ContentServiceImpl;
+import org.acumos.federation.gateway.service.impl.ContentServiceLocalImpl;
 import org.acumos.federation.gateway.service.impl.CatalogServiceImpl;
 import org.acumos.federation.gateway.service.impl.PeerServiceImpl;
 import org.acumos.federation.gateway.service.impl.PeerSubscriptionServiceImpl;
@@ -52,7 +52,8 @@ import org.springframework.scheduling.annotation.EnableScheduling;
                                 AuthenticationConfiguration.class})
 @EnableConfigurationProperties({FederationInterfaceConfiguration.class,
                                                                                                                                LocalInterfaceConfiguration.class,
-                                                                                                                               DockerConfiguration.class})
+                                                                                                                               DockerConfiguration.class,
+                                                                                                                               NexusConfiguration.class})
 @Conditional({GatewayCondition.class})
 @EnableScheduling
 public class GatewayConfiguration {
@@ -83,14 +84,14 @@ public class GatewayConfiguration {
         */
        @Bean
        @Profile({"!local"})
-       public ArtifactService artifactService() {
-               return new ArtifactServiceImpl();
+       public ContentService contentService() {
+               return new ContentServiceImpl();
        }
 
        @Bean
        @Profile({"local"})
-       public ArtifactService localArtifactService() {
-               return new ArtifactServiceLocalImpl();
+       public ContentService localContentService() {
+               return new ContentServiceLocalImpl();
        }
 
 
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/config/NexusConfiguration.java b/gateway/src/main/java/org/acumos/federation/gateway/config/NexusConfiguration.java
new file mode 100644 (file)
index 0000000..2b249f0
--- /dev/null
@@ -0,0 +1,94 @@
+/*-
+ * ===============LICENSE_START=======================================================
+ * Acumos
+ * ===================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
+ * ===================================================================================
+ * This Acumos software file is distributed by AT&T and Tech Mahindra
+ * under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *  
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *  
+ * This file is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ===============LICENSE_END=========================================================
+ */
+
+package org.acumos.federation.gateway.config;
+
+import java.lang.invoke.MethodHandles;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+import org.acumos.nexus.client.RepositoryLocation;
+
+/**
+ * 
+ */
+@Component
+@ConfigurationProperties(prefix = "nexus")
+public class NexusConfiguration {
+
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
+       private RepositoryLocation repositoryLocation;
+       private String                                           groupId;
+       private String                                           nameSeparator;
+
+       public NexusConfiguration() {
+               reset();
+       }
+
+       private void reset() {
+               this.repositoryLocation = new RepositoryLocation();
+               //defaults
+               this.repositoryLocation.setId("1");
+               this.groupId = null;
+               this.nameSeparator = ".";
+       }
+
+       public void setId(String theId) {
+               this.repositoryLocation.setId(theId);
+       }
+
+       public void setUrl(String theUrl) {
+               this.repositoryLocation.setUrl(theUrl);
+  }
+
+       public void setUsername(String theUsername) {
+               this.repositoryLocation.setUsername(theUsername);
+       }
+
+       public void setPassword(String thePassword) {
+               this.repositoryLocation.setPassword(thePassword);
+       }
+
+       public void setProxy(String theProxy) {
+               this.repositoryLocation.setProxy(theProxy);
+       }
+
+       public RepositoryLocation getRepositoryLocation() {
+               return this.repositoryLocation;
+       }
+
+       public void setGroupId(String theGroupId) {
+               this.groupId = theGroupId;
+       }
+
+       public String getGroupId() {
+               return this.groupId;
+       }
+
+       public void setNameSperator(String theNameSeparator) {
+               this.nameSeparator = theNameSeparator;
+       }
+
+       public String getNameSeparator() {
+               return this.nameSeparator;
+       }
+
+}
index 605f95a..e4c3d60 100644 (file)
@@ -30,6 +30,7 @@ import java.util.concurrent.Callable;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
@@ -37,7 +38,7 @@ import org.acumos.federation.gateway.cds.ArtifactType;
 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.service.ArtifactService;
+import org.acumos.federation.gateway.service.ContentService;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.util.Utils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -70,7 +71,7 @@ public class CatalogController extends AbstractController {
        @Autowired
        private CatalogService catalogService;
        @Autowired
-       private ArtifactService artifactService;
+       private ContentService contentService;
 
        /**
         * @param theHttpResponse
@@ -264,7 +265,7 @@ public class CatalogController extends AbstractController {
         *            Solution ID
         * @param theRevisionId
         *            Revision ID
-        * @return List of Published ML Solutions in JSON format.
+        * @return List of solution revision artifacts in JSON format.
         */
        @CrossOrigin
        @PreAuthorize("hasAuthority('CATALOG_ACCESS')")
@@ -291,7 +292,7 @@ public class CatalogController extends AbstractController {
                        else {
                                for (MLPArtifact artifact : solutionRevisionArtifacts) {
                                        if (!context.getPeer().getPeerInfo().isLocal()) {
-                                               encodeArtifact(artifact, theHttpRequest);
+                                               encodeArtifact(theSolutionId, theRevisionId, artifact, theHttpRequest);
                                        }
                                }
                                response = JsonResponse.<List<MLPArtifact>> buildResponse()
@@ -318,18 +319,82 @@ public class CatalogController extends AbstractController {
         *            HttpServletRequest
         * @param theHttpResponse
         *            HttpServletResponse
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
+        * @return List of solution revision documents in JSON format.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('CATALOG_ACCESS')")
+       @ApiOperation(value = "Invoked by Peer Acumos to get a list of solution revision public documents from the local Acumos Instance .", response = MLPArtifact.class, responseContainer = "List")
+       @RequestMapping(value = {
+                       API.Paths.SOLUTION_REVISION_DOCUMENTS }, method = RequestMethod.GET, produces = APPLICATION_JSON)
+       @ResponseBody
+       public JsonResponse<List<MLPDocument>> getSolutionRevisionDocuments(HttpServletRequest theHttpRequest,
+                       HttpServletResponse theHttpResponse, @PathVariable("solutionId") String theSolutionId,
+                       @PathVariable("revisionId") String theRevisionId) {
+               JsonResponse<List<MLPDocument>> response = null;
+               List<MLPDocument> solutionRevisionDocuments = null;
+               ControllerContext context = new ControllerContext();
+               log.debug(EELFLoggerDelegate.debugLogger,
+                               API.Paths.SOLUTION_REVISION_DOCUMENTS + "(" + theSolutionId + "," + theRevisionId + ")");
+               try {
+                       solutionRevisionDocuments = catalogService.getSolutionRevisionDocuments(theSolutionId, theRevisionId, context);
+                       if (null == solutionRevisionDocuments) {
+                               response = JsonResponse.<List<MLPDocument>> buildResponse()
+                                                                                                                               .withMessage("No solution revision " + theSolutionId + "/" + theRevisionId + " is available.")
+                                                                                                                               .build();
+                               theHttpResponse.setStatus(HttpServletResponse.SC_NOT_FOUND);
+                       }
+                       else {
+                               for (MLPDocument document : solutionRevisionDocuments) {
+                                       if (!context.getPeer().getPeerInfo().isLocal()) {
+                                               encodeDocument(theSolutionId, theRevisionId, document, theHttpRequest);
+                                       }
+                               }
+                               response = JsonResponse.<List<MLPDocument>> buildResponse()
+                                                                                                               .withMessage("solution revision documents")
+                                                                                                               .withContent(solutionRevisionDocuments)
+                                                                                                               .build();
+                               theHttpResponse.setStatus(HttpServletResponse.SC_OK);
+                               log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionDocuments provided {} documents",
+                                                       solutionRevisionDocuments.size());
+                       }
+               } 
+               catch (Exception x) {
+                       response = JsonResponse.<List<MLPDocument>> buildErrorResponse()
+                                                                                                                .withError(x)
+                                                                                                                .build();
+                       theHttpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+                       log.error(EELFLoggerDelegate.errorLogger, "An error occured while fetching solution " + theSolutionId + " revision " + theRevisionId + " documents", x);
+               }
+               return response;
+       }
+
+
+       /**
+        * @param theHttpRequest
+        *            HttpServletRequest
+        * @param theHttpResponse
+        *            HttpServletResponse
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
         * @param theArtifactId
         *            Artifact ID
         * @return Archive file of the Artifact for the Solution.
         */
        @CrossOrigin
        @PreAuthorize("hasAuthority('CATALOG_ACCESS')")
-       @ApiOperation(value = "API to download the Machine Learning Artifact of the Machine Learning Solution", response = InputStreamResource.class, code = 200)
+       @ApiOperation(value = "API to download artifact content", response = InputStreamResource.class, code = 200)
        @RequestMapping(value = {
-                       API.Paths.ARTIFACT_DOWNLOAD }, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+                       API.Paths.ARTIFACT_CONTENT }, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
        @ResponseBody
-       public Callable<InputStreamResource> downloadSolutionArtifact(HttpServletRequest theHttpRequest,
-                       HttpServletResponse theHttpResponse, @PathVariable("artifactId") String theArtifactId) {
+       public Callable<InputStreamResource> getArtifactContent(HttpServletRequest theHttpRequest,
+                       HttpServletResponse theHttpResponse, @PathVariable("solutionId") String theSolutionId,
+                       @PathVariable("revisionId") String theRevisionId, @PathVariable("artifactId") String theArtifactId) {
                        
                theHttpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
                theHttpResponse.setHeader("Pragma", "no-cache");
@@ -340,8 +405,8 @@ public class CatalogController extends AbstractController {
                return new Callable<InputStreamResource>() {
                        public InputStreamResource call() throws Exception {
                                try {   
-                                       return artifactService.getArtifactContent(
-                                                                       catalogService.getSolutionRevisionArtifact(theArtifactId, ctx), ctx);
+                                       return contentService.getArtifactContent(
+                                               theSolutionId, theRevisionId, catalogService.getSolutionRevisionArtifact(theArtifactId, ctx), ctx);
                                } 
                                catch (Exception x) {
                                        log.error(EELFLoggerDelegate.errorLogger,
@@ -352,6 +417,50 @@ public class CatalogController extends AbstractController {
                };
        }
 
+       /**
+        * @param theHttpRequest
+        *            HttpServletRequest
+        * @param theHttpResponse
+        *            HttpServletResponse
+        * @param theSolutionId
+        *            Solution ID
+        * @param theRevisionId
+        *            Revision ID
+        * @param theDocumentId
+        *            Document ID
+        * @return Archive file of the Artifact for the Solution.
+        */
+       @CrossOrigin
+       @PreAuthorize("hasAuthority('CATALOG_ACCESS')")
+       @ApiOperation(value = "API to download a documents' content", response = InputStreamResource.class, code = 200)
+       @RequestMapping(value = {
+                       API.Paths.DOCUMENT_CONTENT }, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
+       @ResponseBody
+       public Callable<InputStreamResource> getDocumentContent(HttpServletRequest theHttpRequest,
+                       HttpServletResponse theHttpResponse, @PathVariable("solutionId") String theSolutionId,
+                       @PathVariable("revisionId") String theRevisionId, @PathVariable("documentId") String theDocumentId) {
+                       
+               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 contentService.getDocumentContent(
+                                                                       theSolutionId, theRevisionId, catalogService.getSolutionRevisionDocument(theDocumentId, ctx), ctx);
+                               } 
+                               catch (Exception x) {
+                                       log.error(EELFLoggerDelegate.errorLogger,
+                                               "An error occurred while retrieving artifact content " + theDocumentId, x);
+                                       throw x;
+                               }
+                       }
+               };
+       }
+
        /** */
        private void encodeSolution(MLPSolution theSolution, HttpServletRequest theRequest) throws URISyntaxException {
                //encode the 'origin'
@@ -367,19 +476,19 @@ public class CatalogController extends AbstractController {
        }
        
        /** */
-       private void encodeArtifact(MLPArtifact theArtifact, HttpServletRequest theRequest) throws URISyntaxException {
-
+       private void encodeArtifact(String theSolutionId, String theRevisionId, MLPArtifact theArtifact, HttpServletRequest theRequest)
+                                                                                                                                                                                                                                                                                                               throws URISyntaxException {
                String artifactUri = theArtifact.getUri();
 
                //redirect              
                {
                        URI requestUri = new URI(theRequest.getRequestURL().toString());
-                       URI redirectUri = API.ARTIFACT_DOWNLOAD
+                       URI redirectUri = API.ARTIFACT_CONTENT
                                                                                                .buildUri(
                                                                                                        new URI(requestUri.getScheme(), null, requestUri.getHost(),
                                                                                                                                        requestUri.getPort(), null, null, null).toString(),
-                                                                                                       theArtifact.getArtifactId());
-                       log.debug(EELFLoggerDelegate.debugLogger,       "getSolutionRevisionArtifacts: redirected artifact uri " + redirectUri);
+                                                                                                       theSolutionId, theRevisionId, theArtifact.getArtifactId());
+                       log.debug(EELFLoggerDelegate.debugLogger,       "encodeArtifact: redirected artifact uri " + redirectUri);
                        theArtifact.setUri(redirectUri.toString());
                }
                
@@ -389,7 +498,7 @@ public class CatalogController extends AbstractController {
                        
                                String imageTag = imageId.tag.orNull();
                                if (imageTag != null) {
-                                       log.debug(EELFLoggerDelegate.debugLogger,       "getSolutionRevisionArtifacts: encoded docker image uri to tag " + imageTag);
+                                       log.debug(EELFLoggerDelegate.debugLogger,       "encodeArtifact: encoded docker image uri to tag " + imageTag);
                                        theArtifact.setName(imageTag);
                                        theArtifact.setDescription(imageTag);
                                }
@@ -397,4 +506,22 @@ public class CatalogController extends AbstractController {
                }
        }
        
+       /** */
+       private void encodeDocument(String theSolutionId, String theRevisionId, MLPDocument theDocument, HttpServletRequest theRequest)
+                                                                                                                                                                                                                                                                                                                       throws URISyntaxException {
+               String artifactUri = theDocument.getUri();
+
+               //redirect              
+               {
+                       URI requestUri = new URI(theRequest.getRequestURL().toString());
+                       URI redirectUri = API.DOCUMENT_CONTENT
+                                                                                               .buildUri(
+                                                                                                       new URI(requestUri.getScheme(), null, requestUri.getHost(),
+                                                                                                                                       requestUri.getPort(), null, null, null).toString(),
+                                                                                                       theSolutionId, theRevisionId, theDocument.getDocumentId());
+                       log.debug(EELFLoggerDelegate.debugLogger,       "encodeDocument: redirected document uri " + redirectUri);
+                       theDocument.setUri(redirectUri.toString());
+               }
+       }
+
 }
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
deleted file mode 100644 (file)
index 6e112fa..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-
- * ===============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.acumos.cds.domain.MLPArtifact;
-import org.springframework.core.io.InputStreamResource;
-import org.springframework.core.io.Resource;
-
-/**
- * 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 cc4663e..4b0a446 100644 (file)
@@ -26,9 +26,11 @@ package org.acumos.federation.gateway.service;
 import java.util.List;
 import java.util.Map;
 
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.federation.gateway.cds.Document;
 import org.acumos.federation.gateway.cds.Artifact;
 import org.acumos.federation.gateway.cds.Solution;
 import org.acumos.federation.gateway.cds.SolutionRevision;
@@ -191,7 +193,7 @@ public interface CatalogService {
                                                                                                                                                                                                                                                                                                                                                                        throws ServiceException;
 
        /**
-        * Retrieve artifact content.
+        * Retrieve artifact details.
         *
         * @param theArtifactId
         *            identifier of the acumos artifact whose content needs to be
@@ -203,6 +205,63 @@ public interface CatalogService {
                return getSolutionRevisionArtifact(theArtifactId, selfService());
        }
 
+       /**
+        * Access the list of solution revision documents.
+        * 
+        * @param theSolutionId
+        *            solution identifier (UUID).
+        * @param theRevisionId
+        *            revision identifier (UUID).
+        * @param theContext
+        *            the execution context
+        * @return list of the related documents. 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<MLPDocument> getSolutionRevisionDocuments(String theSolutionId, String theRevisionId,
+                       ServiceContext theContext) throws ServiceException;
+
+       /**
+        * Default solution revision access interface for calls in behalf of the local
+        * Acumos service.
+        *
+        * @param theSolutionId
+        *            solution identifier (UUID).
+        * @param theRevisionId
+        *            revision identifier (UUID).
+        * @return list of the related artifacts
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public default List<MLPDocument> getSolutionRevisionDocuments(String theSolutionId, String theRevisionId) throws ServiceException {
+               return getSolutionRevisionDocuments(theSolutionId, theRevisionId, selfService());
+       }
+
+       /**
+        * Retrieve document details.
+        *
+        * @param theDocumentId
+        *            identifier of the acumos document whose details needs to be
+        *            retrieved
+        * @param theContext
+        *            the execution context
+        * @return Extended document information
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public Document getSolutionRevisionDocument(String theDocumentId, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                       throws ServiceException;
+
+       /**
+        * Retrieve document details.
+        *
+        * @param theDocumentId
+        *            identifier of the acumos document whose details needs to be
+        *            retrieved
+        * @return Extended document information
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public default Document getSolutionRevisionDocument(String theDocumentId) throws ServiceException {
+               return getSolutionRevisionDocument(theDocumentId, 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 ..
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/ContentService.java b/gateway/src/main/java/org/acumos/federation/gateway/service/ContentService.java
new file mode 100644 (file)
index 0000000..f42e502
--- /dev/null
@@ -0,0 +1,167 @@
+/*-
+ * ===============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.acumos.cds.domain.MLPDocument;
+import org.acumos.cds.domain.MLPArtifact;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.core.io.Resource;
+
+/**
+ * Handles access to the content repository. 
+ */
+public interface ContentService {
+
+       /**
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @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(
+                       String theSolutionId, String theRevisionId, MLPArtifact theArtifact, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException;
+
+       /**
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theArtifact
+        *            The CDS representation of artifact metadata
+        * @return resource containing access to the actual artifact content
+        */
+       public default InputStreamResource getArtifactContent(
+                       String theSolutionId, String theRevisionId, MLPArtifact theArtifact)                                    throws ServiceException {
+               return getArtifactContent(theSolutionId, theRevisionId, theArtifact, selfService());
+       }
+
+       /**
+        * If the call is succesful the artifact information is updated with the content uri.
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theArtifact
+        *            The CDS representation of artifact metadata
+        * @param theResource
+        *            the resource providing the artifact content
+        * @param theContext
+        *            the service execution context
+        */
+       public void putArtifactContent(
+               String theSolutionId, String theRevisionId, MLPArtifact theArtifact, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException;
+       /**
+        * If the call is succesful the artifact information is updated with the content uri.
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theArtifact
+        *            The CDS representation of artifact metadata
+        * @param theResource
+        *            the resource providing the artifact content
+        */
+       public default void putArtifactContent(
+               String theSolutionId, String theRevisionId, MLPArtifact theArtifact, Resource theResource)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               putArtifactContent(theSolutionId, theRevisionId, theArtifact, theResource, selfService());
+       }
+
+       /**
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theDocument
+        *            The CDS representation of document metadata
+        * @param theContext
+        *            the execution context
+        * @return resource containing access to the actual document content
+        */
+       public InputStreamResource getDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException;
+
+       /**
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theDocument
+        *            The CDS representation of document metadata
+        * @return resource containing access to the actual document content
+        */
+       public default InputStreamResource getDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument) throws ServiceException {
+
+               return getDocumentContent(theSolutionId, theRevisionId, theDocument, selfService());
+       }
+
+       /**
+        * If the call is succesful the document information is updated with the content uri.
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theDocument
+        *            The CDS representation of document metadata
+        * @param theResource
+        *            the resource providing the document content
+        * @param theContext
+        *            the execution context
+        */
+       public void putDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException;
+
+       /**
+        * If the call is succesful the document information is updated with the content uri.
+        * @param theSolutionId
+        *                                              The solution the revision belongs to
+        * @param theRevisionId
+        *                                              The solution revision the artifact belongs to
+        * @param theDocument
+        *            The CDS representation of document metadata
+        * @param theResource
+        *            the resource providing the document content
+        */
+       public default void putDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, Resource theResource)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               putDocumentContent(theSolutionId, theRevisionId, theDocument, theResource, selfService());
+       }
+
+
+       /**
+        * Provide a self service execution context.
+        */
+       public ServiceContext selfService();
+}
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
deleted file mode 100644 (file)
index 1a41f72..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-/*-
- * ===============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.lang.invoke.MethodHandles;
-
-import org.acumos.cds.domain.MLPArtifact;
-import org.acumos.federation.gateway.cds.ArtifactType;
-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 org.springframework.core.io.InputStreamResource;
-import org.springframework.core.io.Resource;
-import org.springframework.stereotype.Service;
-
-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;
-
-
-/**
- * CDS based implementation of the CatalogService.
- *
- */
-@Service
-public class ArtifactServiceImpl extends AbstractServiceImpl
-                                                                                                                                       implements ArtifactService {
-
-       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
-
-       /**
-        * @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();
-
-                               try (PullImageResultCallback pullResult = new PullImageResultCallback()) {
-                                       docker.pullImageCmd(theArtifact.getUri())
-                                                               .exec(pullResult);
-                                       pullResult.awaitCompletion();
-                               }
-
-                               return new InputStreamResource(docker.saveImageCmd(theArtifact.getUri()).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 artifact 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
-                               Identifier imageId =
-                                       new Identifier(
-                                               new Repository(this.clients.getDockerProperty("registryUrl").toString()),
-                                                                                                        theArtifact.getName() /*the tag*/);
-                               try (PushImageResultCallback pushResult = new PushImageResultCallback()) {
-                                       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);
-               }
-
-       }
-}
index 23dc0d4..295490f 100644 (file)
@@ -37,11 +37,13 @@ import javax.annotation.PostConstruct;
 import org.acumos.cds.AccessTypeCode;
 import org.acumos.cds.ValidationStatusCode;
 import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
 import org.acumos.cds.transport.RestPageRequest;
 import org.acumos.cds.transport.RestPageResponse;
+import org.acumos.federation.gateway.cds.Document;
 import org.acumos.federation.gateway.cds.Artifact;
 import org.acumos.federation.gateway.cds.Solution;
 import org.acumos.federation.gateway.cds.SolutionRevision;
@@ -148,20 +150,6 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                                                                                                                                                                        null,   //authorKeywords
                                                                                                                                                                        null, //publisherKeywords
                                                                                                                                                                        pageRequest);
-/*
-       RestPageResponse<MLPSolution> findPortalSolutions(
-                                                                                                                                                                       String[] nameKeywords,
-                                                                                                                                                                       String[] descriptionKeywords,
-                                                                                                                                                                       boolean active,
-                                                                                                                                                                       String[] userIds,
-                                                                                                                                                                       String[] accessTypeCodes,
-                                                                                                                                                                       String[] modelTypeCodes,
-                                                                                                                                                                       String[] validationStatusCodes,
-                                                                                                                                                                       String[] tags,
-                                                                                                                                                                       String[] authorKeywords,
-                                                                                                                                                                       String[] publisherKeywords,
-                       RestPageRequest pageRequest);
-*/
                                        pageSolutions = pageResponse.getContent();
                                }
                                log.debug(EELFLoggerDelegate.debugLogger, "getSolutions page response {}", pageResponse);
@@ -246,7 +234,16 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                try {
                        SolutionRevision revision =
                                        (SolutionRevision)cdsClient.getSolutionRevision(theSolutionId, theRevisionId);
-                       revision.setArtifacts(cdsClient.getSolutionRevisionArtifacts(theSolutionId, theRevisionId));
+                       revision.setArtifacts(getSolutionRevisionArtifacts(theSolutionId, theRevisionId, theContext.withAttribute(Attributes.cdsClient, cdsClient)));
+                       revision.setDocuments(getSolutionRevisionDocuments(theSolutionId, theRevisionId, theContext.withAttribute(Attributes.cdsClient, cdsClient)));
+                       try {
+                               revision.setRevisionDescription(cdsClient.getRevisionDescription(theRevisionId, AccessTypeCode.PB.name()));
+                       }
+                       catch (HttpStatusCodeException restx) {
+                               if (!Errors.isCDSNotFound(restx))
+                                       throw new ServiceException("Failed to retrieve solution revision description", restx);
+                       }
+       
                        return revision;
                }       
                catch (HttpStatusCodeException restx) {
@@ -263,13 +260,13 @@ public class CatalogServiceImpl extends AbstractServiceImpl
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifacts");
                try {
-                       return getClient().getSolutionRevisionArtifacts(theSolutionId, theRevisionId);
+                       return getClient(theContext).getSolutionRevisionArtifacts(theSolutionId, theRevisionId);
                }
                catch (HttpStatusCodeException restx) {
                        if (Errors.isCDSNotFound(restx))
                                return null;
                        else
-                               throw new ServiceException("Failed to retrieve solution information", restx);
+                               throw new ServiceException("Failed to retrieve solution revision artifacts information", restx);
                }
        }
 
@@ -282,6 +279,7 @@ public class CatalogServiceImpl extends AbstractServiceImpl
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifact");
                try {
+                       //one should check that this belongs to at least one public revision of some solution accessible within the given context ..
                        return (Artifact)getClient().getArtifact(theArtifactId);
                }       
                catch (HttpStatusCodeException restx) {
@@ -292,4 +290,33 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                }
        }
 
+       @Override
+       public List<MLPDocument> getSolutionRevisionDocuments(String theSolutionId, String theRevisionId, ServiceContext theContext) throws ServiceException {
+               log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionDocuments");
+               try {
+                       return getClient(theContext).getSolutionRevisionDocuments(theRevisionId, AccessTypeCode.PB.name());
+               }
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution revision documents information", restx);
+               }
+       }
+
+       @Override
+       public Document getSolutionRevisionDocument(String theDocumentId, ServiceContext theContext) throws ServiceException {
+               log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevisionDocument");
+               try {
+                       //one should check that this has a public visibility within at least one revision of some solution accessible within the given context ..
+                       return (Document)getClient().getDocument(theDocumentId);
+               }       
+               catch (HttpStatusCodeException restx) {
+                       if (Errors.isCDSNotFound(restx))
+                               return null;
+                       else
+                               throw new ServiceException("Failed to retrieve solution revision document information", restx);
+               }
+       }
+
 }
index 0fa1c79..36161b1 100644 (file)
@@ -31,9 +31,11 @@ import java.util.stream.Collectors;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
 import org.acumos.cds.domain.MLPSolutionRevision;
+import org.acumos.federation.gateway.cds.Document;
 import org.acumos.federation.gateway.cds.Artifact;
 import org.acumos.federation.gateway.cds.Mapper;
 import org.acumos.federation.gateway.cds.Solution;
@@ -162,4 +164,29 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
 
                return null;
        }
+       
+       @Override
+       public List<MLPDocument> getSolutionRevisionDocuments(String theSolutionId, String theRevisionId, ServiceContext theContext) throws ServiceException {
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionDocuments");
+
+               SolutionRevision revision = getSolutionRevision(theSolutionId, theRevisionId, theContext);
+               return (revision == null) ? Collections.EMPTY_LIST : (List)revision.getDocuments();
+       }
+
+       @Override
+       public Document getSolutionRevisionDocument(String theDocumentId, ServiceContext theContext) throws ServiceException {
+               log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionDocument");
+               // cumbersome
+               for (Solution solution : this.solutions) {
+                       for (MLPSolutionRevision revision : solution.getRevisions()) {
+                               for (MLPDocument document : ((SolutionRevision)revision).getDocuments()) {
+                                       if (document.getDocumentId().equals(theDocumentId)) {
+                                               return (Document)document;
+                                       }
+                               }
+                       }
+               }
+
+               return null;
+       }
 }
diff --git a/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ContentServiceImpl.java b/gateway/src/main/java/org/acumos/federation/gateway/service/impl/ContentServiceImpl.java
new file mode 100644 (file)
index 0000000..f5f3503
--- /dev/null
@@ -0,0 +1,211 @@
+/*-
+ * ===============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.lang.invoke.MethodHandles;
+
+import org.acumos.cds.AccessTypeCode;
+import org.acumos.cds.domain.MLPDocument;
+import org.acumos.cds.domain.MLPArtifact;
+import org.acumos.federation.gateway.cds.ArtifactType;
+import org.acumos.federation.gateway.config.EELFLoggerDelegate;
+import org.acumos.federation.gateway.config.NexusConfiguration;
+import org.acumos.federation.gateway.config.DockerConfiguration;
+import org.acumos.federation.gateway.service.ContentService;
+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 org.springframework.core.io.InputStreamResource;
+import org.springframework.core.io.Resource;
+import org.springframework.stereotype.Service;
+import org.springframework.beans.factory.annotation.Autowired;
+
+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;
+
+
+/**
+ * Nexus based implementation of the ContentService.
+ *
+ */
+@Service
+public class ContentServiceImpl extends AbstractServiceImpl
+                                                                                                                                       implements ContentService {
+
+       private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
+
+  @Autowired
+  private NexusConfiguration nexusConfig;
+  @Autowired
+  private DockerConfiguration dockerConfig;
+
+       @Override
+       public InputStreamResource getArtifactContent(
+               String theSolutionId, String theRevisionId, 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);
+
+               if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
+                       try {
+                               //pull followed by save
+                               DockerClient docker = this.clients.getDockerClient();
+
+                               try (PullImageResultCallback pullResult = new PullImageResultCallback()) {
+                                       docker.pullImageCmd(theArtifact.getUri())
+                                                               .exec(pullResult);
+                                       pullResult.awaitCompletion();
+                               }
+
+                               return new InputStreamResource(docker.saveImageCmd(theArtifact.getUri()).exec());
+                       }
+                       catch (Exception x) {
+                               log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifact content for docker artifact " + theArtifact, x);
+                               throw new ServiceException("Failed to retrieve artifact content for docker artifact " + theArtifact, x);
+                       }
+               }
+               else {  
+                       return getNexusContent(theArtifact.getUri());
+               }
+       }
+
+       @Override
+       public void putArtifactContent(
+               String theSolutionId, String theRevisionId, MLPArtifact theArtifact, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+
+               if (ArtifactType.DockerImage == ArtifactType.forCode(theArtifact.getArtifactTypeCode())) {
+                       try {
+                               //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
+                               Identifier imageId =
+                                       new Identifier(
+                                               new Repository(dockerConfig.getRegistryUrl().toString()),
+                                                                                                        theArtifact.getName() /*the tag*/);
+                               try (PushImageResultCallback pushResult = new PushImageResultCallback()) {
+                                       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());
+                       }
+                       catch (Exception x) {
+                               log.error(EELFLoggerDelegate.errorLogger,
+                                                                       "Failed to push docker artifact content to Nexus repo", x);
+                               throw new ServiceException("Failed to push docker artifact content to Nexus repo", x);
+                       }
+               }
+               else {
+                       String[] nameParts = splitName(theArtifact.getName());
+                       UploadArtifactInfo info = putNexusContent(
+                               nexusConfig.getGroupId(), nameParts[0], theArtifact.getVersion(), nameParts[1], theResource);
+                       // update artifact with local repo reference
+                       theArtifact.setUri(info.getArtifactMvnPath());
+               }
+       }
+
+       @Override
+       public InputStreamResource getDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               if (theDocument.getUri() == null) {
+                       throw new ServiceException("No document uri available for " + theDocument);
+               }
+               log.info(EELFLoggerDelegate.debugLogger, "Retrieving document content for {}", theDocument);
+               return getNexusContent(theDocument.getUri());
+       }
+
+       @Override
+       public void putDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               String[] nameParts = splitName(theDocument.getName());
+               UploadArtifactInfo info = putNexusContent(
+                               String.join(nexusConfig.getNameSeparator(), nexusConfig.getGroupId(), theSolutionId, theRevisionId), nameParts[0], AccessTypeCode.PB.name(), nameParts[1], theResource);
+               theDocument.setUri(info.getArtifactMvnPath());
+       }
+
+       protected InputStreamResource getNexusContent(String theUri) throws ServiceException {
+               try {
+                       NexusArtifactClient artifactClient = this.clients.getNexusClient();
+                       ByteArrayOutputStream artifactContent = artifactClient.getArtifact(theUri);
+                       log.info(EELFLoggerDelegate.debugLogger, "Retrieved {} bytes of content from {}", artifactContent.size(), theUri);
+                       return new InputStreamResource(
+                                                                               new ByteArrayInputStream(
+                                                                                       artifactContent.toByteArray()
+                                                                       ));
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve content from  " + theUri, x);
+                       throw new ServiceException("Failed to retrieve content from " + theUri, x);
+               }
+       }
+
+       protected UploadArtifactInfo putNexusContent(
+               String theGroupId, String theContentId, String theVersion, String thePackaging, Resource theResource) throws ServiceException {
+
+               try {
+                       UploadArtifactInfo info = this.clients.getNexusClient()
+                                                                                                                                       .uploadArtifact(theGroupId, theContentId, theVersion, thePackaging,
+                                                                                                                                                                                                       theResource.contentLength(), theResource.getInputStream());
+
+                       log.info(EELFLoggerDelegate.debugLogger, "Wrote artifact content to {}", info.getArtifactMvnPath());
+                       return info;
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger,       "Failed to push content to Nexus repo", x);
+                       throw new ServiceException("Failed to push content to Nexus repo", x);
+               }
+       }
+
+       /**
+        * Split a file name into its core name and extension parts.
+        * @param theName file name to split
+        * @return a string array containing the 2 part or null if the part was missing
+        */
+       private String[] splitName(String theName) {
+               int pos = theName.lastIndexOf('.');
+               return (pos < 0) ?
+                       new String[] {theName, "" /*null: better coding but does not facilitate callers*/} :
+                       pos == theName.length() - 1 ? new String[] {theName.substring(0,pos), ""} :
+                                                                                                                                               new String[] {theName.substring(0,pos), theName.substring(pos+1)};
+       }
+}
@@ -24,9 +24,10 @@ import java.io.IOException;
 import java.lang.invoke.MethodHandles;
 import java.net.URI;
 
+import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
-import org.acumos.federation.gateway.service.ArtifactService;
+import org.acumos.federation.gateway.service.ContentService;
 import org.acumos.federation.gateway.service.ServiceContext;
 import org.acumos.federation.gateway.service.ServiceException;
 import org.apache.commons.io.FileUtils;
@@ -35,12 +36,12 @@ import org.springframework.core.io.Resource;
 import org.springframework.stereotype.Service;
 
 /**
- * File based implementation of the ArtifactService.
+ * File based implementation of the ContentService.
  *
  */
 @Service
-public class ArtifactServiceLocalImpl extends AbstractServiceImpl
-                                                                                                                                       implements ArtifactService {
+public class ContentServiceLocalImpl extends AbstractServiceImpl
+                                                                                                                                       implements ContentService {
 
        private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -49,7 +50,8 @@ public class ArtifactServiceLocalImpl extends AbstractServiceImpl
         * @throws ServiceException if failing to retrieve artifact information or retrieve content 
         */
        @Override
-       public InputStreamResource getArtifactContent(MLPArtifact theArtifact, ServiceContext theContext)
+       public InputStreamResource getArtifactContent(
+               String theSolutionId, String theRevisionId, MLPArtifact theArtifact, ServiceContext theContext)
                                                                                                                                                                                                                                                                                                                                                                                        throws ServiceException {
                if (theArtifact.getUri() == null) {
                        throw new ServiceException("No artifact uri available for " + theArtifact);
@@ -67,8 +69,10 @@ public class ArtifactServiceLocalImpl extends AbstractServiceImpl
        /**
         * Should add a configuration parameter for the location of the file.
         */
-       public void putArtifactContent(MLPArtifact theArtifact, Resource theResource) throws ServiceException {
-
+       @Override
+       public void putArtifactContent(
+               String theSolutionId, String theRevisionId, MLPArtifact theArtifact, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
                File target = null;
                try {
                        target = File.createTempFile(theArtifact.getName() + "-" + theArtifact.getVersion(), null /*""*//*,File directory*/);
@@ -81,4 +85,39 @@ public class ArtifactServiceLocalImpl extends AbstractServiceImpl
 
                theArtifact.setUri(target.toURI().toString());
        }       
+
+       @Override
+       public InputStreamResource getDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               if (theDocument.getUri() == null) {
+                       throw new ServiceException("No document uri available for " + theDocument);
+               }
+
+               try {
+                       return new InputStreamResource(new URI(theDocument.getUri()).toURL().openStream());
+               }
+               catch (Exception x) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve document content for document " + theDocument, x);
+                       throw new ServiceException("Failed to retrieve document content for document " + theDocument, x);
+               }
+       }
+
+       @Override
+       public void putDocumentContent(
+               String theSolutionId, String theRevisionId, MLPDocument theDocument, Resource theResource, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               File target = null;
+               try {
+                       target = File.createTempFile(theDocument.getName() + "-" + theDocument.getVersion(), null /*""*//*,File directory*/);
+                       FileUtils.copyInputStreamToFile(theResource.getInputStream(), target);
+               }
+               catch (IOException iox) {
+                       log.error(EELFLoggerDelegate.errorLogger, "Failed to write document content for document " + theDocument, iox);
+                       throw new ServiceException("Failed to write document content for document " + theDocument, iox);
+               }
+
+               theDocument.setUri(target.toURI().toString());
+       }
+
 }
index 608fe21..bfe52c8 100644 (file)
@@ -40,6 +40,7 @@ import org.acumos.cds.domain.MLPSolutionRevision;
 import org.acumos.cds.transport.RestPageRequest;
 import org.acumos.cds.transport.RestPageResponse;
 import org.acumos.federation.gateway.cds.PeerStatus;
+import org.acumos.federation.gateway.cds.Mapper;
 import org.acumos.federation.gateway.common.Clients;
 import org.acumos.federation.gateway.common.FederationClient;
 import org.acumos.nexus.client.NexusArtifactClient;
@@ -156,6 +157,22 @@ public class PeerGatewayTest {
                        mockSolutionRevisionsResponse
                                .addHeader("Content-Length", String.valueOf(mockSolutionRevisions.contentLength()));
 
+                       BasicHttpResponse mockSolutionRevisionResponse = 
+                               new BasicHttpResponse(
+                                       new BasicStatusLine(
+                                               new ProtocolVersion("HTTP",1,1), 200, "Success"));
+
+                       ClassPathResource mockSolutionRevision =
+                               new ClassPathResource("mockPeerSolutionRevisionResponse.json");
+
+                       mockSolutionRevisionResponse.setEntity(
+                               new InputStreamEntity(mockSolutionRevision.getInputStream()));
+                       mockSolutionRevisionResponse
+                               .addHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
+                       mockSolutionRevisionResponse
+                               .addHeader("Content-Length", String.valueOf(mockSolutionRevision.contentLength()));
+
+
                        BasicHttpResponse mockSolutionRevisionArtifactsResponse = 
                                new BasicHttpResponse(
                                        new BasicStatusLine(
@@ -171,6 +188,21 @@ public class PeerGatewayTest {
                        mockSolutionRevisionArtifactsResponse
                                .addHeader("Content-Length", String.valueOf(mockSolutionRevisionArtifacts.contentLength()));
 
+                       BasicHttpResponse mockSolutionRevisionDocumentsResponse = 
+                               new BasicHttpResponse(
+                                       new BasicStatusLine(
+                                               new ProtocolVersion("HTTP",1,1), 200, "Success"));
+
+                       ClassPathResource mockSolutionRevisionDocuments =
+                               new ClassPathResource("mockPeerSolutionRevisionDocumentsResponse.json");
+
+                       mockSolutionRevisionDocumentsResponse.setEntity(
+                               new InputStreamEntity(mockSolutionRevisionDocuments.getInputStream()));
+                       mockSolutionRevisionDocumentsResponse
+                               .addHeader("Content-Type", ContentType.APPLICATION_JSON.toString());
+                       mockSolutionRevisionDocumentsResponse
+                               .addHeader("Content-Length", String.valueOf(mockSolutionRevisionDocuments.contentLength()));
+
                        BasicHttpResponse mockDownloadResponse = 
                                new BasicHttpResponse(
                                        new BasicStatusLine(
@@ -205,7 +237,8 @@ public class PeerGatewayTest {
                                                //client
                                          return new FederationClient(
                   (String)theInvocation.getArguments()[0]/*the URI*/,
-                  federationClient);
+                  federationClient,
+                                                                       Mapper.build());
                                        /* not working as real method relies on the application context
                                                 which is not set because we work on a  mock
                                                try {
@@ -420,8 +453,12 @@ public class PeerGatewayTest {
                                                        return mockSolutionRevisionsResponse;
                                                if (path.endsWith("/artifacts"))
                                                        return mockSolutionRevisionArtifactsResponse;
+                                               if (path.endsWith("/documents"))
+                                                       return mockSolutionRevisionDocumentsResponse;
                                                if (path.endsWith("/download"))
                                                        return mockDownloadResponse;
+                                               if (path.contains("/solutions/") && path.contains("/revisions/"))
+                                                       return mockSolutionRevisionResponse;
 
        System.out.println(" *** Mock unhandled path " + path);
                                                return null;
index fa83200..3f7a7a7 100644 (file)
@@ -131,40 +131,46 @@ public class TestAdapter {
                                        FederationClient fedClient = clients.getFederationClient(this.peer.getApiUrl());
 
                                        List<MLPSolutionRevision> revisions = null;
+                                       Solution sol = null;
                                        try {
-                                               Solution sol = (Solution)fedClient.getSolution(solution.getSolutionId()).getContent();
+                                               sol = (Solution)fedClient.getSolution(solution.getSolutionId()).getContent();
                                                log.info(EELFLoggerDelegate.debugLogger, "retrieved solution {}", solution);
                                                revisions = (List)sol.getRevisions();
                                        }
                                        catch (Exception x) {
-                                               log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve revisions", x);
+                                               log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve solution", x);
                                                continue;
                                        }
+                                       
                                        log.info(EELFLoggerDelegate.debugLogger,
-                                                       "Received {} revisions {}", revisions.size(), revisions);
+                                               "Received {} revisions {}", revisions.size(), revisions);
 
-                                       List<MLPArtifact> artifacts = null;
-                                       try {
-                                               artifacts = (List<MLPArtifact>) fedClient.getArtifacts(solution.getSolutionId(),
-                                                               revisions.get(revisions.size() - 1).getRevisionId()).getContent();
-                                       }
-                                       catch (Exception x) {
-                                               log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifacts", x);
-                                               continue;
-                                       }
-                                       log.info(EELFLoggerDelegate.debugLogger,
-                                                       "Received {} artifacts {}", artifacts.size(), artifacts);
-
-                                       for (MLPArtifact artifact : artifacts) {
-                                               Resource artifactContent = null;
+                                       for (MLPSolutionRevision revision: revisions) {
+                                               List<MLPArtifact> artifacts = null;
                                                try {
-                                                       artifactContent = fedClient.downloadArtifact(artifact.getArtifactId());
-                                                       log.warn(EELFLoggerDelegate.debugLogger, "Received artifact content: "
-                                                                       + new BufferedReader(new InputStreamReader(artifactContent.getInputStream()))
-                                                                                       .lines().collect(Collectors.joining("\n")));
+                                                       artifacts = (List<MLPArtifact>) fedClient.getArtifacts(
+                                                                                                                                                                                               solution.getSolutionId(),       revision.getRevisionId()).getContent();
                                                }
                                                catch (Exception x) {
-                                                       log.error(EELFLoggerDelegate.errorLogger, "Failed to download artifact", x);
+                                                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve artifacts", x);
+                                                       continue;
+                                               }
+                                               log.info(EELFLoggerDelegate.debugLogger,
+                                                               "Received {} artifacts {}", artifacts.size(), artifacts);
+
+                                               for (MLPArtifact artifact : artifacts) {
+                                                       Resource artifactContent = null;
+                                                       try {
+                                                               artifactContent = fedClient.getArtifactContent(
+                                                                                                                                               solution.getSolutionId(), revision.getRevisionId(), artifact.getArtifactId());
+                                                               log.warn(EELFLoggerDelegate.debugLogger, "Received artifact content: "
+                                                                               + new BufferedReader(new InputStreamReader(artifactContent.getInputStream()))
+                                                                                               .lines().collect(Collectors.joining("\n")));
+                                                       }
+                                                       catch (Exception x) {
+                                                               log.error(EELFLoggerDelegate.errorLogger, "Failed to download artifact", x);
+                                                               continue;
+                                                       }
                                                }
                                        }
                                }
diff --git a/gateway/src/test/resources/mockPeerSolutionRevisionDocumentsResponse.json b/gateway/src/test/resources/mockPeerSolutionRevisionDocumentsResponse.json
new file mode 100644 (file)
index 0000000..2b4ec26
--- /dev/null
@@ -0,0 +1,5 @@
+{
+ "error": false,
+ "message": "Success",
+ "content": []
+}
diff --git a/gateway/src/test/resources/mockPeerSolutionRevisionResponse.json b/gateway/src/test/resources/mockPeerSolutionRevisionResponse.json
new file mode 100644 (file)
index 0000000..0770441
--- /dev/null
@@ -0,0 +1,26 @@
+{
+ "error": false,
+ "message": "Success",
+ "content": {
+  "revisionId":"2c7e4481-6e6f-47d9-b7a4-c4e674d2b341",
+  "solutionId":"6793411f-c7a1-4e93-85bc-f91d267541d8",
+  "description":"First attempt",
+  "version":"1.0",
+  "metadata":"acumosa",
+  "userId":"abcdabcd-abcd-abcd-abcd-abcdabcdabcd",
+  "accessTypeCode": "PB",
+  "validationStatusCode": "PS",
+  "created":"2017-08-10",
+  "modified":"2017-08-11",
+  "artifacts":[{
+    "artifactId":"2c2c2c2c-6e6f-47d9-b7a4-c4e674d2b341",
+    "artifactTypeCode":"dk",
+    "description":"First attempt",
+    "size":0,
+    "metadata":"mock artifact",
+    "created":"2017-09-10",
+    "modified":"2017-09-11"
+   }],
+ "documents":[]
+ }
+}
index bc9234e..0ba61f5 100644 (file)
@@ -8,6 +8,8 @@
   "version":"1.0",
   "metadata":"acumosa",
   "userId":"admin",
+  "accessTypeCode": "PB",
+  "validationStatusCode": "PS",
   "created":"2017-08-10",
   "modified":"2017-08-11"
  }]
index 7ef7e1e..3cdcf9d 100644 (file)
@@ -8,7 +8,6 @@
   "active":"true",
   "modelTypeCode":"CL",
   "toolkitTypeCode":"",
-  "validationStatusCode":"",
   "metadata":"acumosa",
   "created":"2017-08-10",
   "modified":"2017-08-11"