[VID-12] Delivery of remaining features for v1.1
[vid.git] / vid-app-common / src / main / java / org / openecomp / vid / asdc / rest / RestfulAsdcClient.java
1 /*-\r
2  * ============LICENSE_START=======================================================\r
3  * VID\r
4  * ================================================================================\r
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.\r
6  * ================================================================================\r
7  * Licensed under the Apache License, Version 2.0 (the "License");\r
8  * you may not use this file except in compliance with the License.\r
9  * You may obtain a copy of the License at\r
10  * \r
11  *      http://www.apache.org/licenses/LICENSE-2.0\r
12  * \r
13  * Unless required by applicable law or agreed to in writing, software\r
14  * distributed under the License is distributed on an "AS IS" BASIS,\r
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
16  * See the License for the specific language governing permissions and\r
17  * limitations under the License.\r
18  * ============LICENSE_END=========================================================\r
19  */\r
20 \r
21 package org.openecomp.vid.asdc.rest;\r
22 \r
23 import java.io.IOException;\r
24 import java.io.InputStream;\r
25 import java.io.FileInputStream;\r
26 import java.io.File;\r
27 import java.net.URI;\r
28 import java.nio.file.Files;\r
29 import java.nio.file.Path;\r
30 import java.nio.file.StandardCopyOption;\r
31 import java.text.DateFormat;\r
32 import java.text.SimpleDateFormat;\r
33 import java.util.Collection;\r
34 import java.util.Collections;\r
35 import java.util.Map;\r
36 import java.util.Map.Entry;\r
37 import java.util.UUID;\r
38 import java.util.zip.ZipFile;\r
39 \r
40 import javax.ws.rs.NotFoundException;\r
41 import javax.ws.rs.ProcessingException;\r
42 import javax.ws.rs.WebApplicationException;\r
43 import javax.ws.rs.client.Client;\r
44 import javax.ws.rs.client.ResponseProcessingException;\r
45 import javax.ws.rs.client.WebTarget;\r
46 import javax.ws.rs.core.GenericType;\r
47 import javax.ws.rs.core.MediaType;\r
48 import javax.ws.rs.core.MultivaluedHashMap;\r
49 \r
50 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;\r
51 import org.openecomp.vid.asdc.AsdcCatalogException;\r
52 import org.openecomp.vid.asdc.AsdcClient;\r
53 import org.openecomp.vid.asdc.beans.Artifact;\r
54 import org.openecomp.vid.asdc.beans.Resource;\r
55 import org.openecomp.vid.asdc.beans.Service;\r
56 import org.openecomp.vid.asdc.beans.tosca.ToscaCsar;\r
57 import org.openecomp.vid.asdc.beans.tosca.ToscaMeta;\r
58 import org.openecomp.vid.asdc.beans.tosca.ToscaModel;\r
59 import org.openecomp.vid.model.ModelConstants;\r
60 import org.yaml.snakeyaml.Yaml;\r
61 import org.yaml.snakeyaml.error.YAMLException;\r
62 \r
63 import org.openecomp.vid.properties.VidProperties;\r
64 import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;\r
65 \r
66 /**\r
67  * The Class RestfulAsdcClient.\r
68  */\r
69 public class RestfulAsdcClient implements AsdcClient {\r
70 \r
71         /** The Constant LOG. */\r
72         private static final EELFLoggerDelegate LOG = EELFLoggerDelegate.getLogger(RestfulAsdcClient.class);\r
73         \r
74         /** The Constant dateFormat. */\r
75         final static DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss:SSSS");\r
76         \r
77         /** The client. */\r
78         private final Client client;\r
79         \r
80         /** The uri. */\r
81         private final URI uri;\r
82         \r
83         /** The common headers. */\r
84         private final MultivaluedHashMap<String, Object> commonHeaders;\r
85         \r
86         /** The auth. */\r
87         private final String auth;\r
88         \r
89         /**\r
90          * The Class Builder.\r
91          */\r
92         public static class Builder {\r
93         \r
94                 /** The client. */\r
95                 private final Client client;\r
96                 \r
97                 /** The uri. */\r
98                 private final URI uri;\r
99                 \r
100                 /** The auth. */\r
101                 private String auth = null;\r
102                 \r
103                 /**\r
104                  * Instantiates a new builder.\r
105                  *\r
106                  * @param client the client\r
107                  * @param uri the uri\r
108                  */\r
109                 public Builder(Client client, URI uri) {\r
110                         this.client = client;\r
111                         this.client.register(JacksonJsonProvider.class);\r
112                         this.uri = uri;\r
113                 }\r
114                 \r
115                 /**\r
116                  * Auth.\r
117                  *\r
118                  * @param auth the auth\r
119                  * @return the builder\r
120                  */\r
121                 public Builder auth(String auth) {\r
122                         this.auth = auth;\r
123                         return this;\r
124                 }\r
125                 \r
126                 /**\r
127                  * Builds the.\r
128                  *\r
129                  * @return the restful asdc client\r
130                  */\r
131                 public RestfulAsdcClient build() {\r
132                         return new RestfulAsdcClient(this);\r
133                 }\r
134         }\r
135         \r
136         /**\r
137          * Instantiates a new restful asdc client.\r
138          *\r
139          * @param builder the builder\r
140          */\r
141         private RestfulAsdcClient(Builder builder) {\r
142                 client = builder.client;\r
143                 uri = builder.uri;\r
144                 auth = builder.auth;\r
145                 \r
146                 commonHeaders = new MultivaluedHashMap<String, Object> ();\r
147                 commonHeaders.put("X-ECOMP-InstanceID", Collections.singletonList((Object) "VID"));\r
148                 commonHeaders.put("Authorization",  Collections.singletonList((Object) (auth)));\r
149         }\r
150         \r
151         /**\r
152          * Gets the client.\r
153          *\r
154          * @return the client\r
155          */\r
156         private Client getClient() { return client; }\r
157         \r
158         /* (non-Javadoc)\r
159          * @see org.openecomp.vid.asdc.AsdcClient#getResource(java.util.UUID)\r
160          */\r
161         public Resource getResource(UUID uuid) throws AsdcCatalogException {\r
162                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_RESOURCE_API_PATH, ModelConstants.DEFAULT_ASDC_RESOURCE_API_PATH);\r
163                 try {\r
164                         return getClient()\r
165                                         .target(uri)\r
166                                         .path(path + "/" + uuid.toString() + "/metadata")\r
167                                         .request(MediaType.APPLICATION_JSON_TYPE)\r
168                                         .headers(commonHeaders)\r
169                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
170                                         .get(Resource.class);\r
171                 } catch (ResponseProcessingException e) {\r
172                         //Couldn't convert response to Java type\r
173                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
174                 } catch (ProcessingException e) {\r
175                         //IO problems during request\r
176                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
177                 } catch (WebApplicationException e) {\r
178                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
179                         throw new AsdcCatalogException(e);\r
180                 }\r
181         }\r
182 \r
183         /* (non-Javadoc)\r
184          * @see org.openecomp.vid.asdc.AsdcClient#getResources()\r
185          */\r
186         public Collection<Resource> getResources() throws AsdcCatalogException {\r
187                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_RESOURCE_API_PATH, ModelConstants.DEFAULT_ASDC_RESOURCE_API_PATH);\r
188                 try {\r
189                         return getClient()\r
190                                         .target(uri)\r
191                                         .path(path)\r
192                                         .request(MediaType.APPLICATION_JSON_TYPE)\r
193                                         .headers(commonHeaders)\r
194                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
195                                         .get(new GenericType<Collection<Resource>> () {});\r
196                 } catch (ResponseProcessingException e) {\r
197                         //Couldn't convert response to Java type\r
198                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
199                 } catch (ProcessingException e) {\r
200                         //IO problems during request\r
201                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
202                 } catch (WebApplicationException e) {\r
203                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
204                         throw new AsdcCatalogException(e);\r
205                 }\r
206         }\r
207 \r
208         /* (non-Javadoc)\r
209          * @see org.openecomp.vid.asdc.AsdcClient#getResources(java.util.Map)\r
210          */\r
211         public Collection<Resource> getResources(Map<String, String[]> filter) throws AsdcCatalogException {\r
212                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_RESOURCE_API_PATH, ModelConstants.DEFAULT_ASDC_RESOURCE_API_PATH);\r
213                 WebTarget target = getClient()\r
214                                 .target(uri)\r
215                                 .path(path);\r
216                 \r
217                 for (Entry<String, String[]> filterEntry : filter.entrySet()) {\r
218                         target = target.queryParam(filterEntry.getKey(), (Object []) filterEntry.getValue());\r
219                 }\r
220                 \r
221                 try {\r
222                         return target.request()\r
223                                         .accept(MediaType.APPLICATION_JSON_TYPE)\r
224                                         .headers(commonHeaders)\r
225                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
226                                         .get(new GenericType<Collection<Resource>> () {});\r
227                 } catch (ResponseProcessingException e) {\r
228                         //Couldn't convert response to Java type\r
229                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
230                 } catch (ProcessingException e) {\r
231                         //IO problems during request\r
232                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
233                 } catch (NotFoundException e) {\r
234                         throw e;\r
235                 } catch (WebApplicationException e) {\r
236                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
237                         throw new AsdcCatalogException(e);\r
238                 }\r
239         }\r
240 \r
241         /* (non-Javadoc)\r
242          * @see org.openecomp.vid.asdc.AsdcClient#getResourceArtifact(java.util.UUID, java.util.UUID)\r
243          */\r
244         public Artifact getResourceArtifact(UUID resourceUuid, UUID artifactUuid) throws AsdcCatalogException {\r
245                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_RESOURCE_API_PATH, ModelConstants.DEFAULT_ASDC_RESOURCE_API_PATH);\r
246                 try {\r
247                         return getClient()\r
248                                         .target(uri)\r
249                                         .path(path + "/" + resourceUuid + "/artifacts/" + artifactUuid)\r
250                                         .request(MediaType.APPLICATION_JSON_TYPE)\r
251                                         .headers(commonHeaders)\r
252                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
253                                         .get(Artifact.class);\r
254                 } catch (ResponseProcessingException e) {\r
255                         //Couldn't convert response to Java type\r
256                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
257                 } catch (ProcessingException e) {\r
258                         //IO problems during request\r
259                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
260                 } catch (WebApplicationException e) {\r
261                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
262                         throw new AsdcCatalogException(e);\r
263                 }\r
264         }\r
265         \r
266         /* (non-Javadoc)\r
267          * @see org.openecomp.vid.asdc.AsdcClient#getService(java.util.UUID)\r
268          */\r
269         public Service getService(UUID uuid) throws AsdcCatalogException {\r
270                 \r
271                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH);\r
272                 try {\r
273                         return getClient()\r
274                                         .target(uri)\r
275                                         .path( path + "/" + uuid.toString() + "/metadata")\r
276                                         .request(MediaType.APPLICATION_JSON)\r
277                                         .headers(commonHeaders)\r
278                                         .get(Service.class);\r
279                 } catch (ResponseProcessingException e) {\r
280                         //Couldn't convert response to Java type\r
281                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
282                 } catch (ProcessingException e) {\r
283                         //IO problems during request\r
284                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
285                 } catch (WebApplicationException e) {\r
286                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
287                         throw new AsdcCatalogException(e);\r
288                 }\r
289         }\r
290 \r
291         /* (non-Javadoc)\r
292          * @see org.openecomp.vid.asdc.AsdcClient#getServices()\r
293          */\r
294         public Collection<Service> getServices() throws AsdcCatalogException {\r
295                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH);\r
296                 try {\r
297                         return getClient()\r
298                                         .target(uri)\r
299                                         .path(path)\r
300                                         .request()\r
301                                         .accept(MediaType.APPLICATION_JSON_TYPE)\r
302                                         .headers(commonHeaders)\r
303                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
304                                         .get(new GenericType<Collection<Service>> () {});\r
305                 } catch (ResponseProcessingException e) {\r
306                         //Couldn't convert response to Java type\r
307                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
308                 } catch (ProcessingException e) {\r
309                         //IO problems during request\r
310                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
311                 } catch (WebApplicationException e) {\r
312                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
313                         throw new AsdcCatalogException(e);\r
314                 }\r
315         }\r
316 \r
317         /* (non-Javadoc)\r
318          * @see org.openecomp.vid.asdc.AsdcClient#getServices(java.util.Map)\r
319          */\r
320         public Collection<Service> getServices(Map<String, String[]> filter) throws AsdcCatalogException {\r
321                 \r
322                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH);\r
323                 WebTarget target = getClient()\r
324                                 .target(uri)\r
325                                 .path(path);\r
326                 \r
327                         \r
328                 for (Entry<String, String[]> filterEntry : filter.entrySet()) {\r
329                         target = target.queryParam(filterEntry.getKey(), (Object []) filterEntry.getValue());\r
330                 }\r
331                 \r
332                 try {\r
333                         return target.request()\r
334                                         .accept(MediaType.APPLICATION_JSON_TYPE)\r
335                                         .headers(commonHeaders)\r
336                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
337                                         .get(new GenericType<Collection<Service>> () {});\r
338                 } catch (ResponseProcessingException e) {\r
339                         //Couldn't convert response to Java type\r
340                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
341                 } catch (ProcessingException e) {\r
342                         //IO problems during request\r
343                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
344                 } catch (NotFoundException e) {\r
345                         throw e;\r
346                 } catch (WebApplicationException e) {\r
347                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
348                         throw new AsdcCatalogException(e);\r
349                 }\r
350         }\r
351         \r
352         /* (non-Javadoc)\r
353          * @see org.openecomp.vid.asdc.AsdcClient#getServiceArtifact(java.util.UUID, java.util.UUID)\r
354          */\r
355         public Artifact getServiceArtifact(UUID serviceUuid, UUID artifactUuid) throws AsdcCatalogException {\r
356                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH);\r
357                 try {\r
358                         return getClient()\r
359                                         .target(uri)\r
360                                         .path(path + "/" + serviceUuid + "/artifacts/" + artifactUuid)\r
361                                         .request(MediaType.APPLICATION_JSON_TYPE)\r
362                                         .headers(commonHeaders)\r
363                                         .header("Content-Type", MediaType.APPLICATION_JSON)\r
364                                         .get(Artifact.class);\r
365                 } catch (ResponseProcessingException e) {\r
366                         //Couldn't convert response to Java type\r
367                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
368                 } catch (ProcessingException e) {\r
369                         //IO problems during request\r
370                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
371                 } catch (WebApplicationException e) {\r
372                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
373                         throw new AsdcCatalogException(e);\r
374                 }\r
375         }\r
376 \r
377         /* (non-Javadoc)\r
378          * @see org.openecomp.vid.asdc.AsdcClient#getResourceToscaModel(java.util.UUID)\r
379          */\r
380         public ToscaCsar getResourceToscaModel(UUID resourceUuid) throws AsdcCatalogException {\r
381                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_RESOURCE_API_PATH, ModelConstants.DEFAULT_ASDC_RESOURCE_API_PATH);\r
382                 try (final InputStream csarInputStream = (InputStream) getClient()\r
383                                 .target(uri)\r
384                                 .path(path + "/" + resourceUuid + "/toscaModel")\r
385                                 .request(MediaType.APPLICATION_OCTET_STREAM_TYPE)\r
386                                 .headers(commonHeaders)\r
387                                 .header("Content-Type", MediaType.APPLICATION_OCTET_STREAM)\r
388                                 .get(InputStream.class)) {\r
389 \r
390                         return getToscaModel(csarInputStream);\r
391                 } catch (IOException e) {\r
392                         throw new AsdcCatalogException("Failed to retrieve resource TOSCA model from ASDC", e);\r
393                 }\r
394         }\r
395 \r
396         /* (non-Javadoc)\r
397          * @see org.openecomp.vid.asdc.AsdcClient#getServiceToscaModel(java.util.UUID)\r
398          */\r
399         public ToscaCsar getServiceToscaModel(UUID serviceUuid) throws AsdcCatalogException {\r
400                 String path = VidProperties.getPropertyWithDefault(ModelConstants.ASDC_SVC_API_PATH, ModelConstants.DEFAULT_ASDC_SVC_API_PATH);\r
401                 try {\r
402                         final InputStream csarInputStream = (InputStream) getClient()\r
403                                         .target(uri)\r
404                                         .path(path + "/" + serviceUuid + "/toscaModel")\r
405                                         .request(MediaType.APPLICATION_OCTET_STREAM_TYPE)\r
406                                         .headers(commonHeaders)\r
407                                         .header("Content-Type", MediaType.APPLICATION_OCTET_STREAM)\r
408                                         .get(InputStream.class);\r
409                                         \r
410                         return getToscaModel(csarInputStream);\r
411                 } catch (ResponseProcessingException e) {\r
412                         //Couldn't convert response to Java type\r
413                         throw new AsdcCatalogException("ASDC response could not be processed", e);\r
414                 } catch (ProcessingException e) {\r
415                         //IO problems during request\r
416                         throw new AsdcCatalogException("Failed to get a response from ASDC service", e);\r
417                 } catch (WebApplicationException e) {\r
418                         //Web service returned data, but the response status wasn't a good one (i.e. non 2xx)\r
419                         throw new AsdcCatalogException(e);\r
420                 }\r
421         }\r
422         \r
423         /**\r
424          * Gets the tosca model.\r
425          *\r
426          * @param csarInputStream the csar input stream\r
427          * @return the tosca model\r
428          * @throws AsdcCatalogException the asdc catalog exception\r
429          */\r
430         private ToscaCsar getToscaModel(InputStream csarInputStream) throws AsdcCatalogException {\r
431                 final Path csarFile;\r
432                 try {\r
433                         csarFile = Files.createTempFile("csar", ".zip");\r
434                         Files.copy(csarInputStream, csarFile, StandardCopyOption.REPLACE_EXISTING);\r
435                 } catch (IOException e) {\r
436                         throw new AsdcCatalogException("Caught IOException while creating CSAR", e);\r
437                 }\r
438                 \r
439                 try (final ZipFile csar = new ZipFile(csarFile.toFile())) {\r
440                         \r
441                         final InputStream toscaMetaStream = csar.getInputStream(csar.getEntry("TOSCA-Metadata/TOSCA.meta"));\r
442                         final ToscaMeta toscaMeta = new ToscaMeta.Builder(toscaMetaStream).build();\r
443                         final String entryDefinitions = toscaMeta.get("Entry-Definitions");\r
444                         final InputStream toscaParentEntryYamlStream = csar.getInputStream(csar.getEntry(entryDefinitions));\r
445                         \r
446                         try {\r
447                                 final Yaml yaml = new Yaml();\r
448                                 final ToscaModel parentModel = yaml.loadAs(toscaParentEntryYamlStream, ToscaModel.class);\r
449         \r
450                                 final ToscaCsar.Builder csarBuilder = new ToscaCsar.Builder(parentModel);\r
451                                 \r
452                                 for (Map<String, Map<String, String>> imports : parentModel.getImports()) {\r
453                                         LOG.debug("imports = " + imports.toString());\r
454                                         for (Entry<String, Map<String, String>> entry : imports.entrySet()) {\r
455                                                 if ( entry.getValue() != null) {\r
456                                                         String fname = entry.getValue().get("file");\r
457                                                         if ( ( fname != null ) && (fname.startsWith("service") || fname.startsWith("resource")) ) {\r
458                                                                 LOG.debug("fname = " + fname);\r
459                                                                 final InputStream toscaChildEntryYamlStream = csar.getInputStream(csar.getEntry("Definitions/" + fname ));\r
460                                                                 final ToscaModel childModel = yaml.loadAs(toscaChildEntryYamlStream, ToscaModel.class);\r
461                                                                 csarBuilder.addVnf(childModel);\r
462                                                         }\r
463                                                 }\r
464                                         }\r
465                                 }\r
466                                 \r
467                                 return csarBuilder.build();\r
468                         } catch (YAMLException e) {\r
469                                 throw new AsdcCatalogException("Caught exception while processing TOSCA YAML", e);\r
470                         }\r
471                 } catch (IOException e) {\r
472                         throw new AsdcCatalogException("Caught IOException while processing CSAR", e);\r
473                 }\r
474         }\r
475 }\r