Fix solution selector defaults. 32/2732/4
authorSerban Jora <sj2381@att.com>
Wed, 5 Sep 2018 20:43:47 +0000 (16:43 -0400)
committerSerban Jora <sj2381@att.com>
Thu, 6 Sep 2018 17:16:54 +0000 (13:16 -0400)
Fix solution tag handling. Moves solution and revision updates to service interface.

Change-Id: Ief5be7f5313af65645dfe66d39963bebf7e561a0
Issue-ID: ACUMOS-1692
Signed-off-by: Serban Jora <sj2381@att.com>
12 files changed:
docs/release-notes.rst
gateway/src/main/java/org/acumos/federation/gateway/adapter/PeerGateway.java
gateway/src/main/java/org/acumos/federation/gateway/cds/SolutionRevision.java
gateway/src/main/java/org/acumos/federation/gateway/controller/ControllerContext.java
gateway/src/main/java/org/acumos/federation/gateway/service/CatalogService.java
gateway/src/main/java/org/acumos/federation/gateway/service/CatalogServiceConfiguration.java
gateway/src/main/java/org/acumos/federation/gateway/service/ServiceContext.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/AbstractServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/CatalogServiceImpl.java
gateway/src/main/java/org/acumos/federation/gateway/service/impl/CatalogServiceLocalImpl.java
gateway/src/main/java/org/acumos/federation/gateway/task/TaskConfiguration.java
gateway/src/test/java/org/acumos/federation/gateway/test/PeerGatewayTest.java

index 917174d..be4790e 100644 (file)
@@ -27,6 +27,8 @@ Version 1.18.1, 2018-09-05
 
 * Simplified catalog solutions lookup
 * Fix 'self' peer not found (ACUMS-1694)
+* Fix solution tag handling
+* Move solution and revision updates to service interface
 
 Version 1.18.0, 2018-09-05
 -------------------------
index 5571d13..5592bc7 100644 (file)
@@ -28,7 +28,10 @@ import java.util.Map;
 import javax.annotation.PostConstruct;
 import javax.annotation.PreDestroy;
 
+//to go away 
 import org.acumos.cds.client.ICommonDataServiceRestClient;
+import org.acumos.federation.gateway.service.impl.AbstractServiceImpl;
+
 import org.acumos.cds.AccessTypeCode;
 import org.acumos.cds.domain.MLPTag;
 import org.acumos.cds.domain.MLPDocument;
@@ -48,6 +51,7 @@ 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.ServiceContext;
 import org.acumos.federation.gateway.service.ContentService;
 import org.acumos.federation.gateway.service.CatalogService;
 import org.acumos.federation.gateway.service.ServiceException;
@@ -154,36 +158,28 @@ public class PeerGateway {
                public void run() {
 
                        log.info(EELFLoggerDelegate.debugLogger, "Received peer " + this.peer + " solutions: " + this.solutions);
-                       ICommonDataServiceRestClient cdsClient = PeerGateway.this.clients.getCDSClient();
+                       ServiceContext ctx = catalog.selfService();
+
                        for (MLPSolution peerSolution : this.solutions) {
                                // Check if the Model already exists in the Local Acumos
                                MLPSolution localSolution = null;
                                log.info(EELFLoggerDelegate.debugLogger, "Processing peer solution {}", peerSolution);
-                               try {
-                                       try {
-                                               localSolution = cdsClient.getSolution(peerSolution.getSolutionId());
-                                       } 
-                                       catch (HttpStatusCodeException scx) {
-                                               if (!Errors.isCDSNotFound(scx)) {
-                                                       log.error(EELFLoggerDelegate.errorLogger, "Failed to check if solution with id "
-                                                               + peerSolution.getSolutionId() + " exists locally, skipping for now. Response says " + scx.getResponseBodyAsString(), scx);
-                                                       continue;
-                                               }
-                                       }
 
-                                       if (localSolution == null) {
-                                               log.info(EELFLoggerDelegate.debugLogger, "Solution Id : " + peerSolution.getSolutionId()
-                                                               + " does not exists locally, adding it to local catalog ");
-                                               localSolution = createMLPSolution(peerSolution, cdsClient);
-                                       }
-                                       else {
-                                               log.info(EELFLoggerDelegate.debugLogger, "Solution Id : " + peerSolution.getSolutionId()
-                                                               + " exists locally, updating local catalog ");
-                                               localSolution = updateMLPSolution(peerSolution, localSolution, cdsClient);
-                                       }
+                               try {
+                                       localSolution = catalog.putSolution(
+                                                                                                                               Solution.buildFrom(peerSolution)
+                                                                                                                                       .withUser(getUserId(this.sub))
+                                                                                                                                       .withSource(this.peer.getPeerId())
+                                                                                                                                       .build(), ctx);
+                               }
+                               catch (ServiceException sx) {
+                                       log.error(EELFLoggerDelegate.errorLogger,
+                                                       "Failed to put solution {} into local catalog", peerSolution, sx);
+                                       continue;
+                               }
 
-                                       addTags(peerSolution, localSolution, cdsClient);
-                                       mapSolution(localSolution, cdsClient);
+                               try {
+                                       mapSolution(localSolution, ctx);
                                }
                                catch (Throwable t) {
                                        log.error(EELFLoggerDelegate.errorLogger,
@@ -192,68 +188,21 @@ public class PeerGateway {
                        }
                }
 
-               private MLPSolution createMLPSolution(MLPSolution peerSolution, ICommonDataServiceRestClient cdsClient) {
-                       log.info(EELFLoggerDelegate.debugLogger,
-                                       "Creating Local MLP Solution for peer solution " + peerSolution);
-
-                       Solution localSolution = Solution.buildFrom(peerSolution)
-                       //should the creted/modified reflect this information or the information we got from the peer ?
-                                                                                                                                       .withUser(getUserId(this.sub))
-                                                                                                                                       .withSource(this.peer.getPeerId())
-                                                                                                                                       //clear the tags and web info for now.
-                                                                                                                                       .withTags(null)
-                                                                                                                                       .withWebStats(null)
-                                                                                                                                       .build();
-                       try {
-                               cdsClient.createSolution(localSolution);        
-                               return localSolution;
-                       }
-                       catch (HttpStatusCodeException restx) {
-                               log.error(EELFLoggerDelegate.errorLogger,
-                                               "createSolution CDS call failed. CDS message is " + restx.getResponseBodyAsString(), restx);
-                               return null;
-                       }
-                       catch (Exception x) {
-                               log.error(EELFLoggerDelegate.errorLogger, "createMLPSolution unexpected failure", x);
-                               return null;
-                       }
-               }
-
-               private MLPSolutionRevision createMLPSolutionRevision(MLPSolutionRevision peerRevision,
-                               ICommonDataServiceRestClient cdsClient) {
-
-                       SolutionRevision localRevision = SolutionRevision.buildFrom(peerRevision)
-                                                                                                                                                                       .withUser(getUserId(this.sub))
-                                                                                                                                                                       .withSource(this.peer.getPeerId())
-                                                                                                                                                                       .withAccessTypeCode(this.sub.getAccessType())
-                                                                                                                                                                       .withValidationStatusCode(this.peer.getValidationStatusCode())
-                                                                                                                                                                       .build();
-                       try {
-                               cdsClient.createSolutionRevision(localRevision);
-                               return localRevision;
-                       }
-                       catch (HttpStatusCodeException restx) {
-                               log.error(EELFLoggerDelegate.errorLogger,
-                                               "createSolutionRevision CDS call failed. CDS message is " + restx.getResponseBodyAsString(),
-                                               restx);
-                               return null;
-                       }
-                       catch (Exception x) {
-                               log.error(EELFLoggerDelegate.errorLogger, "createSolutionRevision unexpected failure", x);
-                               return null;
-                       }
+               //this should go away once the move to service interface based operations is complete
+               //as ugly as they come
+               private ICommonDataServiceRestClient getCDSClient(ServiceContext theContext) {
+                       return (ICommonDataServiceRestClient)theContext.getAttribute(AbstractServiceImpl.Attributes.cdsClient);
                }
 
                private MLPArtifact createMLPArtifact(String theSolutionId, String theRevisionId, MLPArtifact peerArtifact,
-                               ICommonDataServiceRestClient cdsClient) {
+                               ServiceContext theContext) throws Exception {
 
                        Artifact artifact = Artifact.buildFrom(peerArtifact)
                                                                                                                .withUser(getUserId(this.sub))
                                                                                                                .build();
                        try {
-                               cdsClient.createArtifact(artifact);
-                               cdsClient.addSolutionRevisionArtifact(theSolutionId, theRevisionId, artifact.getArtifactId());
-                               return artifact;
+                               getCDSClient(theContext).createArtifact(artifact);
+                               getCDSClient(theContext).addSolutionRevisionArtifact(theSolutionId, theRevisionId, artifact.getArtifactId());
                        }
                        catch (HttpStatusCodeException restx) {
                                log.error(EELFLoggerDelegate.errorLogger,
@@ -262,8 +211,9 @@ public class PeerGateway {
                        }
                        catch (Exception x) {
                                log.error(EELFLoggerDelegate.errorLogger, "createArtifact unexpected failure", x);
-                               return null;
+                               throw x;
                        }
+                       return artifact;
                }
 
                /* we create a new one as nothing is preserved. assumes matching ids. */
@@ -276,14 +226,14 @@ public class PeerGateway {
                }
 
                private MLPDocument createMLPDocument(String theSolutionId, String theRevisionId, MLPDocument peerDocument,
-                               ICommonDataServiceRestClient cdsClient) {
+                               ServiceContext theContext) {
 
                        Document document = Document.buildFrom(peerDocument)
                                                                                                                .withUser(getUserId(this.sub))
                                                                                                                .build();
                        try {
-                               cdsClient.createDocument(document);
-                               cdsClient.addSolutionRevisionDocument(theRevisionId, AccessTypeCode.PB.name(), document.getDocumentId());
+                               getCDSClient(theContext).createDocument(document);
+                               getCDSClient(theContext).addSolutionRevisionDocument(theRevisionId, AccessTypeCode.PB.name(), document.getDocumentId());
                                return document;
                        }
                        catch (HttpStatusCodeException restx) {
@@ -305,72 +255,7 @@ public class PeerGateway {
                                                                .build();
                }
 
-               private MLPSolution updateMLPSolution(final MLPSolution peerSolution, final MLPSolution localSolution,
-                               ICommonDataServiceRestClient cdsClient) {
-                       log.info(EELFLoggerDelegate.debugLogger,
-                                       "Updating Local MLP Solution for peer solution " + peerSolution);
-
-                       if (!peerSolution.getSolutionId().equals(localSolution.getSolutionId()))
-                               throw new IllegalArgumentException("Local and Peer identifier mismatch");
-
-                       //start with the peer solution and pick the few local values we ought to preserve or impose
-                       Solution solution = Solution.buildFrom(peerSolution)
-                                                                                                                       .withUser((Object... args) -> {
-                                                                                                                                       String newUserId = getUserId(this.sub);
-                                                                                                                                               if (!newUserId.equals(localSolution.getUserId())) {
-                                                                                                                                                       // is this solution being updated as part of different/new subscription?
-                                                                                                                                                       log.warn(EELFLoggerDelegate.errorLogger, "updating solution " +localSolution.getSolutionId()
-                                                                                                                                                       + " as part of subscription " + this.sub.getSubId() + " triggers a user change");
-                                                                                                                                               }
-                                                                                                                                               return newUserId;
-                                                                                                                               })
-                                                                                                                       .withSource((Object... args) -> {
-                                                                                                                                       if (localSolution.getSourceId() == null) {
-                                                                                                                                               //this is a local solution that made its way back
-                                                                                                                                               log.info(EELFLoggerDelegate.debugLogger, "Solution " + localSolution.getSolutionId()
-                                                                                                                                               + " as part of subscription " + this.sub.getSubId() + " was originally provisioned locally");
-                                                                                                                                               return null;
-                                                                                                                                       }
-                                                                                                                                       else {
-                                                                                                                                               String newSourceId = this.peer.getPeerId();
-                                                                                                                                               if (!newSourceId.equals(localSolution.getSourceId())) {
-                                                                                                                                                       // we will see this if a solution is available in more than one peer
-                                                                                                                                                       log.warn(EELFLoggerDelegate.errorLogger, "updating solution " +localSolution.getSolutionId()
-                                                                                                                                                       + " as part of subscription " + this.sub.getSubId() + " triggers a source change");
-                                                                                                                                               }
-                                                                                                                                               return newSourceId;
-                                                                                                                                       }
-                                                                                                                               })
-                                                                                                                       .withTags(null)
-                                                                                                                       .withWebStats(null)
-                                                                                                                       .build();
 
-                       try {
-                               cdsClient.updateSolution(solution);
-                               return solution;
-                       }
-                       catch (HttpStatusCodeException restx) {
-                               log.error(EELFLoggerDelegate.errorLogger,
-                                               "updateSolution CDS call failed. CDS message is " + restx.getResponseBodyAsString(), restx);
-                               return null;
-                       }
-                       catch (Exception x) {
-                               log.error(EELFLoggerDelegate.errorLogger, "updateSolution unexpected failure", x);
-                               return null;
-                       }
-               }
-
-               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.
@@ -378,12 +263,12 @@ public class PeerGateway {
                 * @param theSolution
                 *            the local solution who's related information (revisions and
                 *            artifacts) we are trying to sync
-                * @param cdsClient
-                *            CDS client to use in the process
+                * @param theContext
+                *            the context in which we perform the catalog operations
                 * @throws Exception
                 *             any error related to CDS and peer interaction
                 */
-               protected void mapSolution(MLPSolution theSolution, ICommonDataServiceRestClient cdsClient) throws Exception {
+               protected void mapSolution(MLPSolution theSolution, ServiceContext theContext) throws Exception {
 
                        FederationClient fedClient = clients.getFederationClient(this.peer.getApiUrl());
 
@@ -409,7 +294,7 @@ public class PeerGateway {
                        // check if we have locally the latest revision available on the peer
                        List<MLPSolutionRevision> catalogRevisions = Collections.EMPTY_LIST;
                        try {
-                               catalogRevisions = catalog.getSolutionRevisions(theSolution.getSolutionId());
+                               catalogRevisions = catalog.getSolutionRevisions(theSolution.getSolutionId(), theContext);
                        }
                        catch (ServiceException sx) {
                                log.error(EELFLoggerDelegate.errorLogger,
@@ -440,37 +325,30 @@ public class PeerGateway {
                                                                                                                                                .getContent();
                                }
                                catch (Exception x) {
-                                       log.warn(EELFLoggerDelegate.errorLogger, "Failed to retrieve peer acumos artifact details", x);
-                                       throw x;
+                                       log.error(EELFLoggerDelegate.errorLogger, "Failed to retrieve peer acumos artifact details", x);
+                                       continue; //try procecssing the next revision
+                               }
+
+                               try {
+                                       localRevision = catalog.putSolutionRevision(
+                                                                                                                                               SolutionRevision.buildFrom(peerRevision)
+                                                                                                                                                                       .withUser(getUserId(this.sub))
+                                                                                                                                                                       .withSource(this.peer.getPeerId())
+                                                                                                                                                                       .withAccessTypeCode(this.sub.getAccessType())
+                                                                                                                                                                       .withValidationStatusCode(this.peer.getValidationStatusCode())
+                                                                                                                                                                       .build(), theContext);
+                               }
+                               catch (ServiceException sx) {
+                                       log.error(EELFLoggerDelegate.errorLogger,
+                                                       "Failed to put revision " + theSolution.getSolutionId() + "/" + peerRevision.getRevisionId() + " into catalog", sx);
+                                       continue; //try procecssing the next revision
                                }
 
                                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) {
-                                               //cannot map this revision, move onto the next one
-                                               continue;
-                                       }
-                               }
-                               else {
-                                       try {
-                                               localRevision = catalog.getSolutionRevision(
-                                                                                                                               theSolution.getSolutionId(), localRevision.getRevisionId());
-                                       }
-                                       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();
-                               }
+                               List<MLPArtifact> catalogArtifacts = (List)((SolutionRevision)localRevision).getArtifacts();
+                               List<MLPDocument>       catalogDocuments = (List)((SolutionRevision)localRevision).getDocuments();
 
                                final List<MLPArtifact> localArtifacts = catalogArtifacts;
                                // map the artifacts
@@ -486,7 +364,7 @@ public class PeerGateway {
 
                                        if (localArtifact == null) {
                                                localArtifact = createMLPArtifact(theSolution.getSolutionId(), localRevision.getRevisionId(),
-                                                               peerArtifact, cdsClient);
+                                                               peerArtifact, theContext);
                                        }
                                        else {
                                                if (!peerArtifact.getVersion().equals(localArtifact.getVersion())) {
@@ -528,7 +406,7 @@ public class PeerGateway {
 
                                        if (doUpdate) {
                                                try {
-                                                       cdsClient.updateArtifact(localArtifact);
+                                                       getCDSClient(theContext).updateArtifact(localArtifact);
                                                        log.info(EELFLoggerDelegate.debugLogger, "Local artifact updated with local content reference: {}", localArtifact); 
                                                }
                                                catch (HttpStatusCodeException restx) {
@@ -555,7 +433,7 @@ public class PeerGateway {
 
                                        if (localDocument == null) {
                                                localDocument = createMLPDocument(theSolution.getSolutionId(), localRevision.getRevisionId(),
-                                                               peerDocument, cdsClient);
+                                                               peerDocument, theContext);
                                        }
                                        else {
                                                //what if the local document has been modified past the last fetch ??
@@ -598,7 +476,7 @@ public class PeerGateway {
 
                                        if (doUpdate) {
                                                try {
-                                                       cdsClient.updateDocument(localDocument);
+                                                       getCDSClient(theContext).updateDocument(localDocument);
                                                        log.info(EELFLoggerDelegate.debugLogger, "Local document updated with local content reference: {}", localDocument); 
                                                }
                                                catch (HttpStatusCodeException restx) {
@@ -616,12 +494,12 @@ public class PeerGateway {
                                if (peerDescription != null) {
                                        try {
                                                if (catalogDescription == null) {
-                                                       cdsClient.createRevisionDescription(peerDescription);
+                                                       getCDSClient(theContext).createRevisionDescription(peerDescription);
                                                }
                                                else {
                                                        //is this a good enough test ??
                                                        if (peerDescription.getModified().after(catalogDescription.getModified())) {
-                                                               cdsClient.updateRevisionDescription(peerDescription);
+                                                               getCDSClient(theContext).updateRevisionDescription(peerDescription);
                                                        }
                                                }
                                        }
index 9cd557e..07f6787 100644 (file)
@@ -20,6 +20,7 @@
 package org.acumos.federation.gateway.cds;
 
 import java.util.List;
+import java.util.Collections;
 
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPDocument;
@@ -37,8 +38,8 @@ public class SolutionRevision extends MLPSolutionRevision {
                public static final String validationStatusCode = "validationStatusCode";
        };
 
-       private List<? extends MLPArtifact>             artifacts;
-       private List<? extends MLPDocument>             documents;
+       private List<? extends MLPArtifact>             artifacts = Collections.EMPTY_LIST;
+       private List<? extends MLPDocument>             documents = Collections.EMPTY_LIST;
        private MLPRevisionDescription                          description;
 
        public SolutionRevision() {
index ae5cef2..ee98933 100644 (file)
@@ -44,13 +44,18 @@ public class ControllerContext implements ServiceContext {
                return (Peer) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        }
        
-       public ServiceContext withAttribute(String theName, Object theValue) {
+       public Object getAttribute(String theName) {
+               return attributes.get().get(theName);
+       }
+
+       public void setAttribute(String theName, Object theValue) {
                attributes.get().put(theName, theValue);
-               return this;
        }
 
-       public Object getAttribute(String theName) {
-               return attributes.get().get(theName);
+       public ServiceContext withAttribute(String theName, Object theValue) {
+               setAttribute(theName, theValue);
+               return this;
        }
+
        
 }
index 4b0a446..476e3b6 100644 (file)
@@ -100,6 +100,17 @@ public interface CatalogService {
                return getSolution(theSolutionId, selfService());
        }
 
+       /**
+        * Create or update the given solution information set and directly associated information such as tags.
+        * @param theSolution
+        *                                              extended solution information set
+        * @param theContext
+        *            the execution context
+        * @return the solution information in its new service representation
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public Solution putSolution(Solution theSolution, ServiceContext theContext) throws ServiceException; 
+
        /**
         * Provides revision information given a solution identifier.
         * 
@@ -148,6 +159,18 @@ public interface CatalogService {
                return getSolutionRevision(theSolutionId, theRevisionId, selfService());
        }
 
+       /**
+        * Create or update the given solution revision information set.
+        * Should this handle associated information such as artifacts and documents ?
+        * @param theRevision
+        *                                              Extended revision information set including potential artifacts/documents/..
+        * @param theContext
+        *            the execution context
+        * @return the SolutionRevision as it will now be provided by the service.
+        * @throws ServiceException if an error is encoutered during processing
+        */
+       public SolutionRevision putSolutionRevision(SolutionRevision theRevision,       ServiceContext theContext) throws ServiceException; 
+
        /**
         * Access the list of solution revision artifacts.
         * 
index 2f78362..b9970a2 100644 (file)
@@ -51,6 +51,7 @@ public class CatalogServiceConfiguration {
        private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(MethodHandles.lookup().lookupClass());
 
        private Map<String, Object>     solutionsSelector;
+       private Map<String, Object>     solutionsSelectorDefaults;
        private Map<String, Object>     solutionRevisionsSelector;
 
 
@@ -64,13 +65,16 @@ public class CatalogServiceConfiguration {
         * the corresponding field is no longer maintained in the backend. It ca always be re-introduced through configuration.
         */
        private void reset() {
+               this.solutionsSelectorDefaults = new HashMap<String, Object>();
+               // If not otherwise specified last updated since the beggining of times
+               this.solutionsSelectorDefaults.put(Solution.Fields.modified, new Long(1));
+
+               //this selector forces certain criteria such as no client can impose/submit them
                this.solutionsSelector = new HashMap<String, Object>();
                // Fetch only active solutions
                this.solutionsSelector.put(Solution.Fields.active, true);
                // Fetch only Public models
                this.solutionsSelector.put(Solution.Fields.accessTypeCode, AccessTypeCode.PB.toString());
-               // Fetch solutions last updated since the beggining of times
-               this.solutionsSelector.put(Solution.Fields.modified, new Long(1));
 
                this.solutionRevisionsSelector = new HashMap<String, Object>();
                // Fetch only for Public revisions
@@ -80,6 +84,15 @@ public class CatalogServiceConfiguration {
                this.solutionRevisionsSelector = Collections.unmodifiableMap(this.solutionRevisionsSelector);;
        }
 
+       public Map<String, Object> getSolutionsSelectorDefaults() {
+               return this.solutionsSelectorDefaults;
+       }
+
+       public void setSolutionsSelectorDefaults(String theSelector) {
+               this.solutionsSelectorDefaults = Collections.unmodifiableMap(
+                                                                                                                       JsonParserFactory.getJsonParser().parseMap(theSelector));
+  }
+
        public Map<String, Object> getSolutionsSelector() {
                return this.solutionsSelector;
        }
index 251aa02..7da73c1 100644 (file)
@@ -30,13 +30,17 @@ import org.acumos.federation.gateway.security.Peer;
  */
 public interface ServiceContext {
 
-       /*
+       /* Retrieve a context attribute.
         */
-       public ServiceContext withAttribute(String theName, Object theValue);
+       public Object getAttribute(String theName);
 
-       /*
+       /* Attach a context attribute
         */
-       public Object getAttribute(String theName);
+       public void setAttribute(String theName, Object theValue);
+
+       /* Fluent version of setAttribute
+        */
+       public ServiceContext withAttribute(String theName, Object theValue);
 
        /*
         * In who's behalf are we providing the service.
@@ -68,16 +72,25 @@ public interface ServiceContext {
                                peer = thePeer;
                        }
 
+                       @Override
                        public Peer getPeer() { return peer; }
 
-                       public ServiceContext withAttribute(String theName, Object theValue) {
+                       @Override
+                       public Object getAttribute(String theName) {
+                               return attributes.get(theName);
+                       }
+
+                       @Override
+                       public void setAttribute(String theName, Object theValue) {
                                attributes.put(theName, theValue);
-                               return this;
                        }
 
-                       public Object getAttribute(String theName) {
-                               return attributes.get(theName);
+                       @Override
+                       public ServiceContext withAttribute(String theName, Object theValue) {
+                               setAttribute(theName, theValue);
+                               return this;
                        }
+
                };
        }
 }
index f3003d3..4ded12d 100644 (file)
@@ -41,15 +41,23 @@ public abstract class AbstractServiceImpl {
        }
 
        public ICommonDataServiceRestClient getClient(ServiceContext theContext) {
+               return getClient(theContext, false);
+       }
+
+       public ICommonDataServiceRestClient getClient(ServiceContext theContext, boolean doSetClient) {
                ICommonDataServiceRestClient client = (ICommonDataServiceRestClient)theContext.getAttribute(Attributes.cdsClient);
-               if (client == null)
+               if (client == null) {
                        client = getClient();
-
+                       if (doSetClient) {
+                               theContext.setAttribute(Attributes.cdsClient, client);
+                       }
+               }
                return client;
        }
 
        public ServiceContext selfService() {
-               return ServiceContext.forPeer((Peer)appCtx.getBean("self"));            
+               return ServiceContext.forPeer((Peer)appCtx.getBean("self"))
+                                                                                                .withAttribute(Attributes.cdsClient, getClient());             
        }
 
        /**
index 45e0fce..52dc62e 100644 (file)
@@ -31,6 +31,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import javax.annotation.PostConstruct;
@@ -38,6 +39,7 @@ 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.MLPTag;
 import org.acumos.cds.domain.MLPDocument;
 import org.acumos.cds.domain.MLPArtifact;
 import org.acumos.cds.domain.MLPSolution;
@@ -82,7 +84,7 @@ public class CatalogServiceImpl extends AbstractServiceImpl
        public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException {
                log.debug(EELFLoggerDelegate.debugLogger, "getSolutions with selector {}", theSelector);
 
-               Map<String, Object> selector = new HashMap<String, Object>();
+               Map<String, Object> selector = new HashMap<String, Object>(this.config.getSolutionsSelectorDefaults());
                if (theSelector != null)
                        selector.putAll(theSelector);
                //it is essential that this gets done at the end as to force all baseSelector criteria (otherwise a submitted accessTypeCode
@@ -94,7 +96,7 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                RestPageResponse<MLPSolution> pageResponse = null;
                List<MLPSolution> solutions = new ArrayList<MLPSolution>(),
                                                                                        pageSolutions = null;
-               ICommonDataServiceRestClient cdsClient = getClient();
+               ICommonDataServiceRestClient cdsClient = getClient(theContext);
                try {
                        do {
                                log.debug(EELFLoggerDelegate.debugLogger, "getSolutions page {}", pageResponse);
@@ -139,10 +141,10 @@ public class CatalogServiceImpl extends AbstractServiceImpl
        public Solution getSolution(String theSolutionId, ServiceContext theContext) throws ServiceException {
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolution {}", theSolutionId);
-               ICommonDataServiceRestClient cdsClient = getClient();
+               ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
                try {
                        Solution solution = (Solution)cdsClient.getSolution(theSolutionId);
-                       List<MLPSolutionRevision> revisions = getSolutionRevisions(theSolutionId, theContext.withAttribute(Attributes.cdsClient, cdsClient));
+                       List<MLPSolutionRevision> revisions = getSolutionRevisions(theSolutionId, theContext);
 
                        //we can expose this solution only if we can expose at least one revision
                        if (revisions == null || revisions.isEmpty())
@@ -159,6 +161,78 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                }
        }
 
+       @Override       
+       public Solution putSolution(Solution theSolution, ServiceContext theContext) throws ServiceException {
+               
+               log.trace(EELFLoggerDelegate.debugLogger, "putSolution {}", theSolution);
+               ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
+
+               MLPSolution catalogSolution = null;
+               try {
+                       catalogSolution = cdsClient.getSolution(theSolution.getSolutionId());
+               }
+               catch (HttpStatusCodeException scx) {
+                       if (!Errors.isCDSNotFound(scx)) {
+                               log.error(EELFLoggerDelegate.errorLogger, "Failed to check if solution " + theSolution.getSolutionId() + " exists in catalog. CDS says " + scx.getResponseBodyAsString(), scx);
+               throw new ServiceException("Failed to check if solution " + theSolution.getSolutionId() + " exists in catalog", scx);
+                       }
+               }
+
+               //we handle tags separately
+               Set<MLPTag> tags = theSolution.getTags();
+               theSolution.setTags(Collections.EMPTY_SET);
+               //reset the web stats
+               theSolution.setWebStats(null);
+
+               try {
+                       if (catalogSolution == null) {
+                               log.info(EELFLoggerDelegate.debugLogger, "Solution {} does not exists in catalog, adding", theSolution.getSolutionId());
+                               catalogSolution = cdsClient.createSolution(theSolution);        
+       }
+                       else {
+                               log.info(EELFLoggerDelegate.debugLogger, "Solution {} exists in catalog, updating", theSolution.getSolutionId());
+                               //some basic warnings
+                               if (!catalogSolution.getUserId().equals(theSolution.getUserId())) {
+                                       // is this solution being updated as part of different/new subscription?
+                                       log.warn(EELFLoggerDelegate.errorLogger, "Updating solution {} triggers a user change", catalogSolution.getSolutionId());
+                               }
+
+                               if (catalogSolution.getSourceId() == null) {
+                                       //this is a local solution that made its way back
+                                       log.info(EELFLoggerDelegate.debugLogger, "Solution {} was originally provisioned locally", catalogSolution.getSolutionId());
+                               }
+                               else {
+                                       if (!theSolution.getSourceId().equals(catalogSolution.getSourceId())) {
+                                               // we will see this if a solution is available in more than one peer
+                                               log.warn(EELFLoggerDelegate.errorLogger, "Solution {} triggers a source change", catalogSolution.getSolutionId());
+                                       }
+                               }
+                               cdsClient.updateSolution(theSolution);
+                               catalogSolution = theSolution;
+                       }
+               }
+               catch (HttpStatusCodeException scx) {
+                       log.error(EELFLoggerDelegate.errorLogger,       "CDS solution call failed. CDS says " + scx.getResponseBodyAsString(), scx);
+                       throw new ServiceException("CDS solution call failed. CDS says " + scx.getResponseBodyAsString(), scx);
+               }
+
+               //tags: best effort approach
+               for (MLPTag tag: tags) {
+                       try {
+                               cdsClient.addSolutionTag(catalogSolution.getSolutionId(), tag.getTag());
+                       }
+                       catch (HttpStatusCodeException scx) {
+                               //we ignore and keep trying
+                               log.error(EELFLoggerDelegate.errorLogger,       "CDS solution add tag call failed. CDS says " + scx.getResponseBodyAsString(), scx);
+                       }
+               }
+       
+               return Solution.buildFrom(catalogSolution)
+                                                                        .withTags(tags) //this is not accurate as somem might have failed
+                                                                        .withWebStats(null)
+                                                                        .build();
+       }
+
        @Override
        public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext) throws ServiceException {
 
@@ -200,12 +274,12 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                        ServiceContext theContext) throws ServiceException {
 
                log.trace(EELFLoggerDelegate.debugLogger, "getSolutionRevision");
-               ICommonDataServiceRestClient cdsClient = getClient();
+               ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
                try {
                        SolutionRevision revision =
                                        (SolutionRevision)cdsClient.getSolutionRevision(theSolutionId, theRevisionId);
-                       revision.setArtifacts(getSolutionRevisionArtifacts(theSolutionId, theRevisionId, theContext.withAttribute(Attributes.cdsClient, cdsClient)));
-                       revision.setDocuments(getSolutionRevisionDocuments(theSolutionId, theRevisionId, theContext.withAttribute(Attributes.cdsClient, cdsClient)));
+                       revision.setArtifacts(getSolutionRevisionArtifacts(theSolutionId, theRevisionId, theContext));
+                       revision.setDocuments(getSolutionRevisionDocuments(theSolutionId, theRevisionId, theContext));
                        try {
                                revision.setRevisionDescription(cdsClient.getRevisionDescription(theRevisionId, AccessTypeCode.PB.name()));
                        }
@@ -224,6 +298,27 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                }
        }
 
+       @Override
+  public SolutionRevision putSolutionRevision(SolutionRevision theRevision, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               log.trace(EELFLoggerDelegate.debugLogger, "putSolutionRevision {}", theRevision);
+       
+               MLPSolutionRevision catalogRevision = getSolutionRevision(theRevision.getSolutionId(), theRevision.getRevisionId(), theContext);
+               try {
+                       if (catalogRevision == null) {
+                               log.info(EELFLoggerDelegate.debugLogger, "Revision {}/{} does not exists in catalog, adding", theRevision.getSolutionId(), theRevision.getRevisionId());
+                               catalogRevision = SolutionRevision.buildFrom(getClient(theContext).createSolutionRevision(theRevision))
+                                                                                                                                                                       .build();       
+       }
+               }
+               catch (HttpStatusCodeException scx) {
+                       log.error(EELFLoggerDelegate.errorLogger,       "CDS solution revision call failed. CDS says " + scx.getResponseBodyAsString(), scx);
+                       throw new ServiceException("CDS solution revision call failed. CDS says " + scx.getResponseBodyAsString(), scx);
+               }
+
+               return (SolutionRevision)catalogRevision;
+       }
+
        @Override
        public List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId,
                        ServiceContext theContext) throws ServiceException {
@@ -250,7 +345,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);
+                       return (Artifact)getClient(theContext).getArtifact(theArtifactId);
                }       
                catch (HttpStatusCodeException restx) {
                        if (Errors.isCDSNotFound(restx))
@@ -279,7 +374,7 @@ public class CatalogServiceImpl extends AbstractServiceImpl
                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);
+                       return (Document)getClient(theContext).getDocument(theDocumentId);
                }       
                catch (HttpStatusCodeException restx) {
                        if (Errors.isCDSNotFound(restx))
index 36161b1..d861290 100644 (file)
@@ -120,6 +120,13 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
                }).findFirst().orElse(null);
        }
 
+       @Override       
+       public Solution putSolution(Solution theSolution, ServiceContext theContext) throws ServiceException {
+               
+               log.trace(EELFLoggerDelegate.debugLogger, "putSolution {}", theSolution);
+               return theSolution;
+       }
+
        @Override
        public List<MLPSolutionRevision> getSolutionRevisions(final String theSolutionId, ServiceContext theContext) throws ServiceException {
 
@@ -138,6 +145,13 @@ public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements
                                                .filter(rev -> rev.getRevisionId().equals(theRevisionId)).findFirst().orElse(null);
        }
 
+       @Override
+  public SolutionRevision putSolutionRevision(SolutionRevision theRevision, ServiceContext theContext)
+                                                                                                                                                                                                                                                                                                                                                                                                                               throws ServiceException {
+               log.trace(EELFLoggerDelegate.debugLogger, "putSolutionRevision {}", theRevision);
+               return theRevision;     
+       }
+
        @Override
        public List<MLPArtifact> getSolutionRevisionArtifacts(final String theSolutionId, final String theRevisionId,
                        ServiceContext theContext) throws ServiceException {
index b96f98e..64ba662 100644 (file)
@@ -25,12 +25,16 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
+import org.springframework.scheduling.annotation.EnableScheduling;
 
 
 /**
  * Provides the beans used to setup the peer subscription tasks.
  */
 @Configuration
+@EnableScheduling
 @EnableAutoConfiguration
 //@ConfigurationProperties(prefix = "task", ignoreInvalidFields = true)
 public class TaskConfiguration {
@@ -38,6 +42,11 @@ public class TaskConfiguration {
        public TaskConfiguration() {
        }
 
+       @Bean
+       public TaskScheduler taskScheduler() {
+    return new ConcurrentTaskScheduler();
+       }
+
        /**
         */
        @Bean
index 002ae56..8148913 100644 (file)
@@ -73,6 +73,8 @@ import org.springframework.boot.test.mock.mockito.MockBean;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.io.ClassPathResource;
 import org.springframework.test.context.junit4.SpringRunner;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.client.HttpClientErrorException;
 
 
 /**
@@ -409,6 +411,15 @@ public class PeerGatewayTest {
                                        }
                                });
 
+                       //pretend the revision does not exist
+                       when(
+                               this.cdsClient.getSolutionRevision(
+                                       any(String.class), any(String.class)
+                               )
+                       ) 
+                       .thenThrow(new HttpClientErrorException(
+                                                                                       HttpStatus.BAD_REQUEST, "No such revision", "{\"error\":\"No revision with ID whatever\"}".getBytes(), null));
+
                        when(
                                this.cdsClient.createSolutionRevision(
                                        any(MLPSolutionRevision.class)