Fix handling of docker image with no tags
[federation.git] / gateway / src / main / java / org / acumos / federation / gateway / service / impl / CatalogServiceLocalImpl.java
1 /*-
2  * ===============LICENSE_START=======================================================
3  * Acumos
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
11  *  
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *  
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=========================================================
19  */
20
21 package org.acumos.federation.gateway.service.impl;
22
23 import java.net.URI;
24 import java.net.URISyntaxException;
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.InputStream;
30 import java.io.IOException;
31 import java.util.Arrays;
32 import java.util.ArrayList;
33 import java.util.LinkedList;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Collections;
38 import java.util.stream.Collectors;
39
40 import javax.annotation.PostConstruct;
41 import javax.annotation.PreDestroy;
42
43 import com.fasterxml.jackson.annotation.JsonIgnore;
44 import com.fasterxml.jackson.annotation.JsonProperty;
45 import com.fasterxml.jackson.databind.MappingIterator;
46 import com.fasterxml.jackson.databind.ObjectMapper;
47 import com.fasterxml.jackson.databind.ObjectReader;
48
49 import org.apache.commons.io.FileUtils;
50
51 import org.acumos.federation.gateway.config.EELFLoggerDelegate;
52 import org.acumos.federation.gateway.service.CatalogService;
53 import org.acumos.federation.gateway.service.ServiceContext;
54 import org.acumos.federation.gateway.service.ServiceException;
55 import org.acumos.federation.gateway.util.Utils;
56
57 import org.acumos.cds.AccessTypeCode;
58 import org.acumos.cds.ValidationStatusCode;
59 import org.acumos.cds.client.ICommonDataServiceRestClient;
60 import org.acumos.cds.domain.MLPArtifact;
61 import org.acumos.cds.domain.MLPSolution;
62 import org.acumos.cds.domain.MLPSolutionRevision;
63 import org.acumos.cds.transport.RestPageResponse;
64
65 import org.springframework.beans.factory.annotation.Autowired;
66 import org.springframework.beans.factory.BeanInitializationException;
67 import org.springframework.core.env.Environment;
68 import org.springframework.core.io.InputStreamResource;
69 import org.springframework.stereotype.Service;
70 import org.springframework.context.annotation.Conditional;
71 import org.springframework.boot.context.properties.ConfigurationProperties;
72
73
74 /**
75  * 
76  *
77  */
78 @Service
79 @ConfigurationProperties(prefix = "catalogLocal")
80 public class CatalogServiceLocalImpl extends AbstractServiceLocalImpl implements CatalogService {
81
82         private static final EELFLoggerDelegate log = EELFLoggerDelegate.getLogger(CatalogServiceLocalImpl.class.getName());
83
84         private List<FLPSolution> solutions;
85
86         @PostConstruct
87         public void initService() {
88
89                 checkResource();
90                 try {
91                         watcher.watchOn(this.resource.getURL().toURI(), (uri) -> {
92                                 loadSolutionsCatalogInfo();
93                         });
94
95                 } catch (IOException | URISyntaxException iox) {
96                         log.info(EELFLoggerDelegate.errorLogger, "Catalog watcher registration failed for " + this.resource, iox);
97                 }
98
99                 loadSolutionsCatalogInfo();
100
101                 // Done
102                 log.debug(EELFLoggerDelegate.debugLogger, "Local CatalogService available");
103         }
104
105         @PreDestroy
106         public void cleanupService() {
107         }
108
109         /** */
110         private void loadSolutionsCatalogInfo() {
111                 synchronized (this) {
112                         try {
113                                 ObjectReader objectReader = new ObjectMapper().reader(FLPSolution.class);
114                                 MappingIterator objectIterator = objectReader.readValues(this.resource.getURL());
115                                 this.solutions = objectIterator.readAll();
116                                 log.info(EELFLoggerDelegate.debugLogger, "loaded " + this.solutions.size() + " solutions");
117                         } catch (Exception x) {
118                                 throw new BeanInitializationException("Failed to load solutions catalog from " + this.resource, x);
119                         }
120                 }
121         }
122
123         @Override
124         public List<MLPSolution> getSolutions(Map<String, ?> theSelector, ServiceContext theContext) throws ServiceException {
125
126                 log.debug(EELFLoggerDelegate.debugLogger, "getSolutions, selector {}", theSelector);
127
128                 return solutions.stream()
129                         .filter(solution -> ServiceImpl.isSelectable(solution, theSelector))
130                         .collect(Collectors.toList());
131         }
132
133         @Override
134         public MLPSolution getSolution(final String theSolutionId, ServiceContext theContext) throws ServiceException {
135
136                 log.debug(EELFLoggerDelegate.debugLogger, "getSolution");
137                 return solutions.stream().filter(solution -> {
138                         return theSolutionId.equals(solution.getSolutionId());
139                 }).findFirst().orElse(null);
140         }
141
142         @Override
143         public List<MLPSolutionRevision> getSolutionRevisions(final String theSolutionId, ServiceContext theContext) throws ServiceException {
144
145                 log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisions");
146                 FLPSolution solution = this.solutions.stream().filter(sol -> sol.getSolutionId().equals(theSolutionId))
147                                 .findFirst().orElse(null);
148
149                 return (solution == null) ? null : solution.getMLPRevisions();
150         }
151
152         @Override
153         public MLPSolutionRevision getSolutionRevision(String theSolutionId, String theRevisionId,
154                         ServiceContext theContext) throws ServiceException  {
155
156                 log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevision");
157                 List<MLPSolutionRevision> revisions = getSolutionRevisions(theSolutionId, theContext);
158
159                 if (revisions == null)
160                         return null;
161
162                 return revisions.stream().filter(rev -> rev.getRevisionId().equals(theRevisionId)).findFirst().orElse(null);
163         }
164
165         @Override
166         public List<MLPArtifact> getSolutionRevisionArtifacts(final String theSolutionId, final String theRevisionId,
167                         ServiceContext theContext) throws ServiceException {
168                 log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifacts");
169
170                 FLPRevision revision = (FLPRevision) getSolutionRevision(theSolutionId, theRevisionId, theContext);
171
172                 return (revision == null) ? null : revision.getArtifacts();
173         }
174
175         @Override
176         public MLPArtifact getSolutionRevisionArtifact(String theArtifactId, ServiceContext theContext) 
177                                                                                                                                                                                                                                                                                                                                                                                                 throws ServiceException {
178                 log.debug(EELFLoggerDelegate.debugLogger, "getSolutionRevisionArtifact");
179                 // cumbersome
180                 for (FLPSolution solution : this.solutions) {
181                         for (FLPRevision revision : solution.getRevisions()) {
182                                 for (MLPArtifact artifact : revision.getArtifacts()) {
183                                         if (artifact.getArtifactId().equals(theArtifactId)) {
184                                                 return artifact;
185                                         }
186                                 }
187                         }
188                 }
189
190                 return null;
191         }
192
193         /** */
194         public static class FLPSolution extends MLPSolution {
195
196                 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
197                 private List<FLPRevision> revisions = Collections.EMPTY_LIST;
198
199                 // @JsonIgnore
200                 public List<FLPRevision> getRevisions() {
201                         return this.revisions;
202                 }
203
204                 // @JsonIgnore
205                 protected List<MLPSolutionRevision> getMLPRevisions() {
206                         return this.revisions == null ? null
207                                         : this.revisions.stream().map(rev -> (MLPSolutionRevision) rev).collect(Collectors.toList());
208                 }
209
210                 public void setRevisions(List<FLPRevision> theRevisions) {
211                         this.revisions = theRevisions;
212                 }
213
214         }
215
216         /** */
217         public static class FLPRevision extends MLPSolutionRevision {
218
219                 @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
220                 private List<MLPArtifact> artifacts = Collections.EMPTY_LIST;
221
222                 // @JsonIgnore
223                 // we send a deep clone as the client can modify them and we only have one copy
224                 public List<MLPArtifact> getArtifacts() {
225                         List<MLPArtifact> copy = new LinkedList<MLPArtifact>();
226                         for (MLPArtifact artifact : this.artifacts) {
227                                 MLPArtifact acopy = new MLPArtifact();
228                                 acopy.setArtifactId(artifact.getArtifactId());
229                                 acopy.setArtifactTypeCode(artifact.getArtifactTypeCode());
230                                 acopy.setDescription(artifact.getDescription());
231                                 acopy.setUri(artifact.getUri());
232                                 acopy.setName(artifact.getName());
233                                 acopy.setSize(artifact.getSize());
234                                 acopy.setOwnerId(artifact.getOwnerId());
235                                 acopy.setCreated(artifact.getCreated());
236                                 acopy.setModified(artifact.getModified());
237                                 acopy.setMetadata(artifact.getMetadata());
238
239                                 copy.add(acopy);
240                         }
241                         return copy;
242                 }
243
244                 public void setArtifacts(List<MLPArtifact> theArtifacts) {
245                         this.artifacts = theArtifacts;
246                 }
247         }
248
249 }