2 * ===============LICENSE_START=======================================================
4 * ===================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6 * ===================================================================================
7 * This Acumos software file is distributed by AT&T and Tech Mahindra
8 * under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * This file is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ===============LICENSE_END=========================================================
24 package org.acumos.federation.gateway.service.impl;
26 import java.lang.invoke.MethodHandles;
27 import java.time.Instant;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.List;
35 import java.util.function.Predicate;
36 import java.util.function.Function;
37 import java.util.stream.Collectors;
39 import javax.annotation.PostConstruct;
41 import org.acumos.cds.AccessTypeCode;
42 import org.acumos.cds.client.ICommonDataServiceRestClient;
43 import org.acumos.cds.domain.MLPArtifact;
44 import org.acumos.cds.domain.MLPDocument;
45 import org.acumos.cds.domain.MLPSolution;
46 import org.acumos.cds.domain.MLPSolutionRevision;
47 import org.acumos.cds.domain.MLPTag;
48 import org.acumos.cds.transport.RestPageRequest;
49 import org.acumos.cds.transport.RestPageResponse;
50 import org.acumos.federation.gateway.cds.AccessType;
51 import org.acumos.federation.gateway.cds.Artifact;
52 import org.acumos.federation.gateway.cds.Document;
53 import org.acumos.federation.gateway.cds.Solution;
54 import org.acumos.federation.gateway.cds.SolutionRevision;
55 import org.acumos.federation.gateway.cds.TimestampedEntity;
56 import org.acumos.federation.gateway.service.CatalogService;
57 import org.acumos.federation.gateway.service.CatalogServiceConfiguration;
58 import org.acumos.federation.gateway.service.ServiceContext;
59 import org.acumos.federation.gateway.service.ServiceException;
60 import org.acumos.federation.gateway.util.Errors;
61 import org.apache.commons.beanutils.PropertyUtils;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64 import org.springframework.beans.factory.annotation.Autowired;
65 import org.springframework.stereotype.Service;
66 import org.springframework.web.client.HttpStatusCodeException;
69 * CDS based implementation of the CatalogService.
73 public class CatalogServiceImpl extends AbstractServiceImpl
74 implements CatalogService {
76 private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
78 private static final List<String> allATs = new ArrayList<String>();
81 for (AccessType atc: AccessType.values()) {
82 allATs.add(atc.code());
87 private CatalogServiceConfiguration config;
90 public void initService() {
94 public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException {
95 log.debug("getSolutions with selector {}", theSelector);
97 Map<String, Object> selector = new HashMap<String, Object>(this.config.getSolutionsSelectorDefaults());
98 if (theSelector != null)
99 selector.putAll(theSelector);
100 //it is essential that this gets done at the end as to force all baseSelector criteria (otherwise a submitted accessTypeCode
101 //could overwrite the basic one end expose non public solutions ..).
102 selector.putAll(this.config.getSolutionsSelector());
103 log.debug("getSolutions with full selector {}", selector);
105 RestPageRequest pageRequest = new RestPageRequest(0, this.cdsConfig.getPageSize());
106 RestPageResponse<MLPSolution> pageResponse = null;
107 List<MLPSolution> solutions = new ArrayList<MLPSolution>(),
108 pageSolutions = null;
109 ICommonDataServiceRestClient cdsClient = getClient(theContext);
111 Predicate<MLPSolution> matcher = ServiceImpl.compileSelector(selector);
112 String catid = (String)selector.get(Solution.Fields.catalogId);
113 Function<RestPageRequest, RestPageResponse<MLPSolution>> pager = null;
115 pager = page -> cdsClient.getSolutionsInCatalog(catid, page);
117 boolean active = (Boolean)selector.getOrDefault(Solution.Fields.active, Boolean.TRUE);
118 Object o = selector.getOrDefault(Solution.Fields.accessTypeCode, allATs);
119 String[] codes = null;
120 if (o instanceof String) {
121 codes = new String[] { (String)o };
123 codes = ((List<String>)o).toArray(new String[0]);
125 String[] xcodes = codes;
126 Instant since = Instant.ofEpochSecond((Long)selector.get(Solution.Fields.modified));
127 pager = page -> cdsClient.findSolutionsByDate(active, xcodes, since, page);
130 log.debug("getSolutions page {}", pageResponse);
131 pageResponse = pager.apply(pageRequest);
133 log.debug("getSolutions page response {}", pageResponse);
134 //we need to post-process all other selection criteria
135 pageSolutions = pageResponse.getContent().stream()
137 .collect(Collectors.toList());
138 log.debug("getSolutions page selection {}", pageSolutions);
140 pageRequest.setPage(pageResponse.getNumber() + 1);
141 solutions.addAll(pageSolutions);
142 } while (!pageResponse.isLast());
144 catch (HttpStatusCodeException restx) {
145 if (Errors.isCDSNotFound(restx))
146 return Collections.EMPTY_LIST;
148 log.debug("getSolutions failed {}: {}", restx, restx.getResponseBodyAsString());
149 throw new ServiceException("Failed to retrieve solutions", restx);
153 log.debug("getSolutions: solutions count {}", solutions.size());
158 public Solution getSolution(String theSolutionId, ServiceContext theContext) throws ServiceException {
160 log.trace("getSolution {}", theSolutionId);
161 ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
163 Solution solution = (Solution)cdsClient.getSolution(theSolutionId);
164 List<MLPSolutionRevision> revisions = getSolutionRevisions(theSolutionId, theContext);
166 //we can expose this solution only if we can expose at least one revision
167 if (revisions == null || revisions.isEmpty())
170 solution.setRevisions(revisions);
173 catch (HttpStatusCodeException restx) {
174 if (Errors.isCDSNotFound(restx))
177 throw new ServiceException("Failed to retrieve solution information", restx);
182 public Solution putSolution(Solution theSolution, ServiceContext theContext) throws ServiceException {
184 log.trace("putSolution {}", theSolution);
185 ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
187 //we handle tags separately
188 Set<MLPTag> tags = theSolution.getTags();
189 theSolution.setTags(Collections.EMPTY_SET);
192 if (theSolution.getCreated() == TimestampedEntity.ORIGIN) {
193 theSolution = (Solution)cdsClient.createSolution(theSolution);
196 cdsClient.updateSolution(theSolution);
199 catch (HttpStatusCodeException scx) {
200 log.error("CDS solution call failed. CDS says " + scx.getResponseBodyAsString(), scx);
201 throw new ServiceException("CDS solution call failed. CDS says " + scx.getResponseBodyAsString(), scx);
203 catch (Exception x) {
204 log.error("Solution handling unexpected failure", x);
205 throw new ServiceException("Solution handling unexpected failure", x);
208 //tags: best effort approach
209 for (MLPTag tag: tags) {
211 cdsClient.addSolutionTag(theSolution.getSolutionId(), tag.getTag());
213 catch (HttpStatusCodeException scx) {
214 //we ignore and keep trying
215 log.error("CDS solution add tag call failed. CDS says " + scx.getResponseBodyAsString(), scx);
219 //set back the tags; should we only set back those that succeded ?
220 theSolution.setTags(tags);
226 public List<MLPSolutionRevision> getSolutionRevisions(String theSolutionId, ServiceContext theContext) throws ServiceException {
228 log.trace("getSolutionRevisions {}", theSolutionId);
230 List<MLPSolutionRevision> revisions = getClient(theContext).getSolutionRevisions(theSolutionId);
231 //make sure we only expose revisions according to the filter
232 if (revisions != null) {
233 log.trace("getSolutionRevisions {}: got {} revisions", theSolutionId, revisions.size());
236 .filter(revision -> this.config.getSolutionRevisionsSelector().entrySet().stream()
239 log.trace("getSolutionRevisions verifying filter: revision property value {} vs filter value {}", PropertyUtils.getProperty(revision, s.getKey()), s.getValue());
240 return PropertyUtils.getProperty(revision, s.getKey()).equals(s.getValue());
242 catch (Exception x) {
243 log.trace("getSolutionRevisions failed to verify filter", x);
248 .collect(Collectors.toList());
252 catch (HttpStatusCodeException restx) {
253 if (Errors.isCDSNotFound(restx))
256 throw new ServiceException("Failed to retrieve solution revision information", restx);
262 public SolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId,
263 ServiceContext theContext) throws ServiceException {
265 log.trace("getSolutionRevision");
266 ICommonDataServiceRestClient cdsClient = getClient(theContext, true);
268 SolutionRevision revision =
269 (SolutionRevision)cdsClient.getSolutionRevision(theSolutionId, theRevisionId);
270 revision.setArtifacts(getSolutionRevisionArtifacts(theSolutionId, theRevisionId, theContext));
271 revision.setDocuments(getSolutionRevisionDocuments(theSolutionId, theRevisionId, theContext));
273 revision.setRevisionDescription(cdsClient.getRevisionDescription(theRevisionId, AccessTypeCode.PB.name()));
275 catch (HttpStatusCodeException restx) {
276 if (!Errors.isCDSNotFound(restx))
277 throw new ServiceException("Failed to retrieve solution revision description", restx);
282 catch (HttpStatusCodeException restx) {
283 if (Errors.isCDSNotFound(restx))
286 throw new ServiceException("Failed to retrieve solution revision information", restx);
291 public SolutionRevision putSolutionRevision(SolutionRevision theRevision, ServiceContext theContext)
292 throws ServiceException {
293 log.trace("putSolutionRevision {}", theRevision);
296 if (theRevision.getCreated() == TimestampedEntity.ORIGIN) {
297 theRevision = (SolutionRevision)getClient(theContext).createSolutionRevision(theRevision);
300 getClient(theContext).updateSolutionRevision(theRevision);
303 catch (HttpStatusCodeException scx) {
304 log.error("CDS solution revision call failed. CDS says " + scx.getResponseBodyAsString(), scx);
305 throw new ServiceException("CDS solution revision call failed. CDS says " + scx.getResponseBodyAsString(), scx);
307 catch (Exception x) {
308 log.error("Solution revision handling unexpected failure", x);
309 throw new ServiceException("Solution revision handling unexpected failure", x);
316 public List<MLPArtifact> getSolutionRevisionArtifacts(String theSolutionId, String theRevisionId,
317 ServiceContext theContext) throws ServiceException {
319 log.trace("getSolutionRevisionArtifacts");
321 return getClient(theContext).getSolutionRevisionArtifacts(theSolutionId, theRevisionId);
323 catch (HttpStatusCodeException restx) {
324 if (Errors.isCDSNotFound(restx))
327 throw new ServiceException("Failed to retrieve solution revision artifacts information", restx);
332 * @return catalog artifact representation
333 * @throws ServiceException if failing to retrieve artifact information or retrieve content
336 public Artifact getSolutionRevisionArtifact(String theArtifactId, ServiceContext theContext) throws ServiceException {
338 log.trace("getSolutionRevisionArtifact");
340 //one should check that this belongs to at least one public revision of some solution accessible within the given context ..
341 return (Artifact)getClient(theContext).getArtifact(theArtifactId);
343 catch (HttpStatusCodeException restx) {
344 if (Errors.isCDSNotFound(restx))
347 throw new ServiceException("Failed to retrieve solution revision artifact information", restx);
352 public List<MLPDocument> getSolutionRevisionDocuments(String theSolutionId, String theRevisionId, ServiceContext theContext) throws ServiceException {
353 log.trace("getSolutionRevisionDocuments");
355 return getClient(theContext).getSolutionRevisionDocuments(theRevisionId, AccessTypeCode.PB.name());
357 catch (HttpStatusCodeException restx) {
358 if (Errors.isCDSNotFound(restx))
361 throw new ServiceException("Failed to retrieve solution revision documents information", restx);
366 public Document getSolutionRevisionDocument(String theDocumentId, ServiceContext theContext) throws ServiceException {
367 log.trace("getSolutionRevisionDocument");
369 //one should check that this has a public visibility within at least one revision of some solution accessible within the given context ..
370 return (Document)getClient(theContext).getDocument(theDocumentId);
372 catch (HttpStatusCodeException restx) {
373 if (Errors.isCDSNotFound(restx))
376 throw new ServiceException("Failed to retrieve solution revision document information", restx);