DCAE-D be initial commit
[sdc/dcae-d/dt-be-main.git] / dcaedt_catalog / asdc / src / main / java / org / onap / sdc / dcae / catalog / asdc / ASDC.java
1 package org.onap.sdc.dcae.catalog.asdc;
2
3 import java.net.URI;
4 import java.net.URISyntaxException;
5
6 import java.io.File;
7 import java.io.IOException;
8 import java.io.UncheckedIOException;
9
10 import java.util.List;
11 import java.util.Set;
12 import java.util.UUID;
13 import java.util.Collections;
14
15 import java.util.function.UnaryOperator;
16
17 import javax.annotation.PostConstruct;
18
19 import org.onap.sdc.common.onaplog.OnapLoggerDebug;
20 import org.onap.sdc.common.onaplog.OnapLoggerError;
21 import org.onap.sdc.common.onaplog.Enums.LogLevel;
22 import org.onap.sdc.dcae.enums.ArtifactGroupType;
23 import org.onap.sdc.dcae.enums.ArtifactType;
24 import org.onap.sdc.dcae.composition.restmodels.sdc.ResourceDetailed;
25 import org.springframework.http.MediaType;
26 import org.springframework.http.HttpHeaders;
27 import org.springframework.http.HttpRequest;
28 import org.springframework.http.HttpMethod;
29 import org.springframework.http.HttpEntity;
30 import org.springframework.http.RequestEntity;
31 import org.springframework.http.ResponseEntity;
32 import org.springframework.http.client.AsyncClientHttpRequestExecution;
33 import org.springframework.http.client.AsyncClientHttpRequestInterceptor;
34 import org.springframework.http.client.ClientHttpResponse;
35 import org.springframework.web.client.AsyncRestTemplate;
36 import org.springframework.web.client.RestClientException;
37 import org.springframework.web.client.HttpClientErrorException;
38 import org.springframework.http.converter.HttpMessageConverter;
39
40 import org.springframework.util.Base64Utils;
41 //import org.springframework.util.DigestUtils;
42 import org.apache.commons.codec.digest.DigestUtils;
43
44 import org.springframework.stereotype.Component;
45 import org.springframework.context.annotation.Scope;
46 import org.springframework.scheduling.annotation.Scheduled;
47 import org.springframework.beans.factory.annotation.Autowired;
48
49 import org.springframework.util.concurrent.ListenableFuture;
50 import org.springframework.util.concurrent.ListenableFutureCallback;
51
52 import org.apache.commons.io.FileUtils;
53 import org.apache.commons.lang3.StringUtils;
54
55 import org.json.JSONObject;
56 import org.onap.sdc.dcae.catalog.commons.Action;
57 import org.onap.sdc.dcae.catalog.commons.Future;
58 import org.onap.sdc.dcae.catalog.commons.Futures;
59 import org.onap.sdc.dcae.catalog.commons.JSONHttpMessageConverter;
60 import org.onap.sdc.dcae.composition.util.DcaeBeConstants;
61 import org.onap.sdc.dcae.composition.util.SystemProperties;
62 import org.json.JSONArray;
63
64 import org.apache.commons.cli.BasicParser;
65 import org.apache.commons.cli.CommandLine;
66 import org.apache.commons.cli.CommandLineParser;
67 import org.apache.commons.cli.HelpFormatter;
68 import org.apache.commons.cli.OptionBuilder;
69 import org.apache.commons.cli.Options;
70 import org.apache.commons.cli.ParseException;
71
72
73 @Component("asdc")
74 @Scope("singleton")
75 //@ConfigurationProperties(prefix="asdc")
76 public class ASDC {
77
78         public static enum AssetType {
79                 resource,
80                 service,
81                 product
82         }
83
84 //      public static enum ArtifactType {
85 //              DCAE_TOSCA,
86 //              DCAE_JSON,
87 //              DCAE_POLICY,
88 //              DCAE_DOC,
89 //              DCAE_EVENT,
90 //              DCAE_INVENTORY_TOSCA,
91 //              DCAE_INVENTORY_JSON,
92 //              DCAE_INVENTORY_POLICY,
93 //              DCAE_INVENTORY_DOC,
94 //              DCAE_INVENTORY_BLUEPRINT,
95 //              DCAE_INVENTORY_EVENT,
96 //              HEAT,
97 //              HEAT_VOL,
98 //              HEAT_NET,
99 //              HEAT_NESTED,
100 //              HEAT_ARTIFACT,
101 //              HEAT_ENV,
102 //              OTHER
103 //      }
104
105 //      public static enum ArtifactGroupType {
106 //              DEPLOYMENT,
107 //              INFORMATIONAL
108 //      }
109
110         public static enum LifecycleState {
111                 Checkin,
112                 Checkout,
113                 Certify,
114                 undocheckout
115         }
116
117         
118 //      @Retention(RetentionPolicy.RUNTIME)
119 //      @Target(ElementType.METHOD)
120 //      public @interface Mandatory {
121 //      }
122
123         protected static OnapLoggerError errLogger = OnapLoggerError.getInstance();
124         protected static OnapLoggerDebug debugLogger = OnapLoggerDebug.getInstance();
125         
126         @Autowired
127         private SystemProperties systemProperties;
128
129         private URI                     rootUri;
130         private String  rootPath = "/sdc/v1/catalog/";
131         private String  user,
132                                                                         passwd;
133         private String  instanceId;
134
135
136         public void setUri(URI theUri) {
137                 //theUri = URI.create(systemProperties.getProperties().getProperty(SystemProperties.ASDC_CATALOG_URL));
138                 String userInfo = theUri.getUserInfo();
139                 if (userInfo != null) {
140                         String[] userInfoParts = userInfo.split(":");
141                         setUser(userInfoParts[0]);
142                         if (userInfoParts.length > 1)
143                                 setPassword(userInfoParts[1]);
144                 }
145                 String fragment = theUri.getFragment();
146                 if (fragment == null)
147                         throw new IllegalArgumentException("The URI must contain a fragment specification, to be used as ASDC instance id");
148                 setInstanceId(fragment);
149
150                 try {
151                         this.rootUri = new URI(theUri.getScheme(), null, theUri.getHost(), theUri.getPort(), theUri.getPath(), theUri.getQuery(), null);
152                 }
153                 catch (URISyntaxException urix) {
154                         throw new IllegalArgumentException("Invalid uri", urix);
155                 }
156         }
157
158         public URI getUri() {
159                 return this.rootUri;    
160         }
161
162         public void setUser(String theUser) {
163                 this.user = theUser;
164         }
165
166         public String getUser() {
167                 return this.user;
168         }
169
170         public void setPassword(String thePassword) {
171                 this.passwd = thePassword;
172         }
173
174         public String getPassword() {
175                 return this.passwd;
176         }
177
178         public void setInstanceId(String theId) {
179                 this.instanceId = theId;
180         }
181
182         public String getInstanceId() {
183                 return this.instanceId;
184         }
185         
186         public void setRootPath(String thePath) {
187                 this.rootPath = systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_ROOTPATH);
188         }
189
190         public String getRootPath() {
191                 return systemProperties.getProperties().getProperty(DcaeBeConstants.Config.ASDC_ROOTPATH);
192         }
193
194     @Scheduled(fixedRateString = "${beans.context.scripts.updateCheckFrequency?:60000}")
195         public void checkForUpdates() { 
196         }
197
198         @PostConstruct
199         public void initASDC() {
200         }
201
202         public <T> Future<T> getResources(Class<T> theType) {
203                 return getAssets(AssetType.resource, theType);
204         }
205         
206         public Future<JSONArray> getResources() {
207                 return getAssets(AssetType.resource, JSONArray.class);
208         }
209         
210         public <T> Future<T> getResources(Class<T> theType, String theCategory, String theSubCategory) {
211                 return getAssets(AssetType.resource, theType, theCategory, theSubCategory);
212         }
213         
214         public Future<JSONArray> getResources(String category, String subCategory, String resourceType) {
215                 return getAssets(AssetType.resource, JSONArray.class, category, subCategory, resourceType);
216         }
217
218         public <T> Future<T> getServices(Class<T> theType) {
219                 return getAssets(AssetType.service, theType);
220         }
221         
222         public Future<JSONArray> getServices() {
223                 return getAssets(AssetType.service, JSONArray.class);
224         }
225         
226         public <T> Future<T> getServices(Class<T> theType, String theCategory, String theSubCategory) {
227                 return getAssets(AssetType.service, theType, theCategory, theSubCategory);
228         }
229         
230         public Future<JSONArray> getServices(String theCategory, String theSubCategory) {
231                 return getAssets(AssetType.service, JSONArray.class, theCategory, theSubCategory);
232         }
233
234         public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType) {
235                 return fetch(refAssets(theAssetType), theType);
236         }
237         
238         public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType) {
239                 return (() -> fetch(refAssets(theAssetType), theType));
240         }
241         
242         public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType,
243                                                                                                                                  String theCategory, String theSubCategory) {
244                 return getAssets(theAssetType, theType, theCategory, theSubCategory, null);
245         }
246
247         public <T> Future<T> getAssets(AssetType theAssetType, Class<T> theType,
248                                                                                                                                  String theCategory, String theSubCategory, String theResourceType) {
249                 return fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType);
250         }
251         
252         public <T> Action<T> getAssetsAction(AssetType theAssetType, Class<T> theType,
253                                                                                                                                                          String theCategory, String theSubCategory, String theResourceType) {
254                 return (() -> fetch(refAssets(theAssetType) + filter(theCategory, theSubCategory, theResourceType), theType));
255         }
256         
257         protected String refAssets(AssetType theAssetType) {
258                 return this.rootPath + theAssetType + "s/";
259         }
260
261         private String filter(String theCategory, String theSubCategory, String theResourceType) {
262                 StringBuilder filter = null;
263                 if (theCategory != null) {
264                         filter = new StringBuilder();
265                         filter.append("?category=")
266                                                 .append(theCategory);
267                         if (theSubCategory != null) {
268                                 filter.append("&subCategory=")
269                                                         .append(theSubCategory);
270                                 if (theResourceType != null) {
271                                         filter.append("&resourceType=")
272                                                                 .append(theResourceType);
273                                 }
274                         }
275                 }
276                 return filter == null ? "" : filter.toString();
277         }
278
279         protected String refAsset(AssetType theAssetType, UUID theId) {
280                 return this.rootPath + theAssetType + "s/" + theId;
281         }
282         
283         public <T> Future<T> getResource(UUID theId, Class<T> theType) {
284                 return getAsset(AssetType.resource, theId, theType);
285         }
286         
287         public Future<JSONObject> getResource(UUID theId) {
288                 return getAsset(AssetType.resource, theId, JSONObject.class);
289         }
290
291         public Future<ResourceDetailed> getSDCResource(UUID theId) {
292                 return getAsset(AssetType.resource, theId, ResourceDetailed.class);
293         }
294
295
296         public <T> Future<T> getService(UUID theId, Class<T> theType) {
297                 return getAsset(AssetType.service, theId, theType);
298         }
299         
300         public Future<JSONObject> getService(UUID theId) {
301                 return getAsset(AssetType.service, theId, JSONObject.class);
302         }
303
304         public <T> Future<T> getAsset(AssetType theAssetType, UUID theId, Class<T> theType) {
305                 return fetch(refAsset(theAssetType, theId) + "/metadata", theType);
306         }
307         
308         public <T> Action<T> getAssetAction(AssetType theAssetType, UUID theId, Class<T> theType) {
309                 return (() -> fetch(refAsset(theAssetType, theId) + "/metadata", theType));
310         }
311
312         public Future<byte[]> getResourceArchive(UUID theId) {
313                 return getAssetArchive(AssetType.resource, theId);
314         }
315
316         public Future<byte[]> getServiceArchive(UUID theId) {
317                 return getAssetArchive(AssetType.service, theId);
318         }
319
320         public Future<byte[]> getAssetArchive(AssetType theAssetType, UUID theId) {
321                 return fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class);
322         }
323
324         public Action<byte[]> getAssetArchiveAction(AssetType theAssetType, UUID theId) {
325                 return (() -> fetch(refAsset(theAssetType, theId) + "/toscaModel", byte[].class));
326         }
327
328         public Future<JSONObject> checkinResource(UUID theId, String theUser, String theMessage) {
329                 return cycleAsset(AssetType.resource, theId, LifecycleState.Checkin, theUser, theMessage);
330         }
331
332         public Future<JSONObject> checkinService(UUID theId, String theUser, String theMessage) {
333                 return cycleAsset(AssetType.service, theId, LifecycleState.Checkin, theUser, theMessage);
334         }
335
336         public Future<JSONObject> checkoutResource(UUID theId, String theUser, String theMessage) {
337                 return cycleAsset(AssetType.resource, theId, LifecycleState.Checkout, theUser, theMessage);
338         }
339
340         public Future<JSONObject> checkoutService(UUID theId, String theUser, String theMessage) {
341                 return cycleAsset(AssetType.service, theId, LifecycleState.Checkout, theUser, theMessage);
342         }
343         
344         public Future<JSONObject> certifyResource(UUID theId, String theUser, String theMessage) {
345                 return cycleAsset(AssetType.resource, theId, LifecycleState.Certify, theUser, theMessage);
346         }
347
348         public Future<JSONObject> certifyService(UUID theId, String theUser, String theMessage) {
349                 return cycleAsset(AssetType.service, theId, LifecycleState.Certify, theUser, theMessage);
350         }
351
352         /* Normally theMessage is mandatory (and we'd use put instead of putOpt) but .. not so for undocheckout ..
353          */
354         public Future<JSONObject> cycleAsset(AssetType theAssetType, UUID theId, LifecycleState theState,
355                                                                                                                                                          String theUser, String theMessage) {
356                 return post(refAsset(theAssetType, theId)       + "/lifecycleState/" + theState,
357                                                           (headers) -> prepareHeaders(headers)
358                                                                                                                         .header("USER_ID", theUser),
359                                                                 new JSONObject().putOpt("userRemarks", theMessage));
360         }
361
362         protected String refAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theAssetInstance, UUID theArtifactId) {
363                 return refAsset(theAssetType, theAssetId) + "/resourceInstances/" + theAssetInstance + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId));
364         }
365
366         protected String refAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) {
367                 return refAsset(theAssetType, theAssetId) + "/artifacts" + (theArtifactId == null ? "" : ("/" + theArtifactId));
368         }
369         
370         public <T> Future<T> getResourceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) {
371                 return getAssetArtifact(AssetType.resource, theAssetId, theArtifactId, theType);
372         }
373         
374         public <T> Future<T> getServiceArtifact(UUID theAssetId, UUID theArtifactId, Class<T> theType) {
375                 return getAssetArtifact(AssetType.service, theAssetId, theArtifactId, theType);
376         }
377         
378         public <T> Future<T> getResourceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) {
379                 return getAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId, theType);
380         }
381         
382         public <T> Future<T> getServiceInstanceArtifact(UUID theAssetId, UUID theArtifactId, String theInstance, Class<T> theType) {
383                 return getAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId, theType);
384         }
385
386         public <T> Future<T> getAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) {
387                 return fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType);
388         }
389         
390         public <T> Action<T> getAssetArtifactAction(AssetType theAssetType, UUID theAssetId, UUID theArtifactId, Class<T> theType) {
391                 return (() -> fetch(refAssetArtifact(theAssetType, theAssetId, theArtifactId), theType));
392         }
393         
394         public <T> Future<T> getAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) {
395                 return fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType);
396         }
397         
398         public <T> Action<T> getAssetInstanceArtifactAction(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId, Class<T> theType) {
399                 return (() -> fetch(refAssetInstanceArtifact(theAssetType, theAssetId, theInstance, theArtifactId), theType));
400         }
401         
402         public ArtifactUploadAction createResourceArtifact(UUID theAssetId) {
403                 return createAssetArtifact(AssetType.resource, theAssetId);
404         }
405         
406         public ArtifactUploadAction createServiceArtifact(UUID theAssetId) {
407                 return createAssetArtifact(AssetType.service, theAssetId);
408         }
409         
410         public ArtifactUploadAction createResourceInstanceArtifact(UUID theAssetId, String theInstance) {
411                 return createAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance);
412         }
413         
414         public ArtifactUploadAction createServiceInstanceArtifact(UUID theAssetId, String theInstance) {
415                 return createAssetInstanceArtifact(AssetType.service, theAssetId, theInstance);
416         }
417
418         public ArtifactUploadAction createAssetArtifact(AssetType theAssetType, UUID theAssetId) {
419                 return new ArtifactUploadAction()
420                                                                         .ofAsset(theAssetType, theAssetId);
421         }
422         
423         public ArtifactUploadAction createAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance) {
424                 return new ArtifactUploadAction()
425                                                                         .ofAssetInstance(theAssetType, theAssetId, theInstance);
426         }
427
428         public ArtifactUpdateAction updateResourceArtifact(UUID theAssetId, JSONObject theArtifactInfo) {
429                 return updateAssetArtifact(AssetType.resource, theAssetId, theArtifactInfo);
430         }
431         
432         public ArtifactUpdateAction updateResourceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
433                 return updateAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactInfo);
434         }
435         
436         public ArtifactUpdateAction updateServiceArtifact(UUID theAssetId, JSONObject theArtifactInfo) {
437                 return updateAssetArtifact(AssetType.service, theAssetId, theArtifactInfo);
438         }
439         
440         public ArtifactUpdateAction updateServiceInstanceArtifact(UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
441                 return updateAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactInfo);
442         }
443
444         public ArtifactUpdateAction updateAssetArtifact(AssetType theAssetType, UUID theAssetId, JSONObject theArtifactInfo) {
445                 return new ArtifactUpdateAction(theArtifactInfo)
446                                                                         .ofAsset(theAssetType, theAssetId);
447         }
448         
449         public ArtifactUpdateAction updateAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, JSONObject theArtifactInfo) {
450                 return new ArtifactUpdateAction(theArtifactInfo)
451                                                                         .ofAssetInstance(theAssetType, theAssetId, theInstance);
452         }
453
454         public ArtifactDeleteAction deleteResourceArtifact(UUID theAssetId, UUID theArtifactId) {
455                 return deleteAssetArtifact(AssetType.resource, theAssetId, theArtifactId);
456         }
457         
458         public ArtifactDeleteAction deleteResourceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) {
459                 return deleteAssetInstanceArtifact(AssetType.resource, theAssetId, theInstance, theArtifactId);
460         }
461         
462         public ArtifactDeleteAction deleteServiceArtifact(UUID theAssetId, UUID theArtifactId) {
463                 return deleteAssetArtifact(AssetType.service, theAssetId, theArtifactId);
464         }
465         
466         public ArtifactDeleteAction deleteServiceInstanceArtifact(UUID theAssetId, String theInstance, UUID theArtifactId) {
467                 return deleteAssetInstanceArtifact(AssetType.service, theAssetId, theInstance, theArtifactId);
468         }
469
470         public ArtifactDeleteAction deleteAssetArtifact(AssetType theAssetType, UUID theAssetId, UUID theArtifactId) {
471                 return new ArtifactDeleteAction(theArtifactId)
472                                                                         .ofAsset(theAssetType, theAssetId);
473         }
474         
475         public ArtifactDeleteAction deleteAssetInstanceArtifact(AssetType theAssetType, UUID theAssetId, String theInstance, UUID theArtifactId) {
476                 return new ArtifactDeleteAction(theArtifactId)
477                                                                         .ofAssetInstance(theAssetType, theAssetId, theInstance);
478         }
479
480         
481         public abstract class ASDCAction<A extends ASDCAction<A, T>, T> implements Action<T> { 
482
483                 protected JSONObject    info;                           //info passed to asdc as request body
484                 protected String                        operatorId;             //id of the SDC user performing the action
485
486                 protected ASDCAction(JSONObject theInfo) {
487                         this.info = theInfo;
488                 }
489                 
490                 protected abstract A self(); 
491
492                 protected ASDC asdc() {
493                         return ASDC.this;
494                 }
495         
496                 protected A withInfo(JSONObject theInfo) {
497                         merge(this.info, theInfo);
498                         return self();
499                 }
500         
501                 public A with(String theProperty, Object theValue) {
502                         info.put(theProperty, theValue);
503                         return self();
504                 }
505
506                 public A withOperator(String theOperator) {
507                         this.operatorId = theOperator;
508                         return self();                  
509                 }
510                 
511                 protected abstract String[] mandatoryInfoEntries();
512         
513                 protected void checkOperatorId() {
514                         if (this.operatorId == null) {
515                                 throw new IllegalStateException("No operator id was provided");
516                         }
517                 }
518
519                 protected void checkMandatoryInfo() {
520                         for (String field: mandatoryInfoEntries()) {
521                                 if (!info.has(field))                   
522                                         throw new IllegalStateException("No '" + field + "' was provided");
523                         }
524                 }
525                 
526                 protected void checkMandatory() {
527                         checkOperatorId();
528                         checkMandatoryInfo();
529                 }
530         }
531
532         protected static final String[] artifactMandatoryEntries = new String[] {};
533
534         /**
535    * We use teh same API to operate on artifacts attached to assets or to their instances
536          */
537         public abstract class ASDCArtifactAction<A extends ASDCArtifactAction<A>> extends ASDCAction<A, JSONObject> {
538
539                 protected AssetType             assetType;
540                 protected UUID                          assetId;
541                 protected String                        assetInstance;
542
543                 protected ASDCArtifactAction(JSONObject theInfo) {
544                         super(theInfo);
545                 }
546                 
547                 protected A ofAsset(AssetType theAssetType, UUID theAssetId) {
548                         this.assetType = theAssetType;
549                         this.assetId = theAssetId;
550                         return self();                  
551                 }
552                 
553                 protected A ofAssetInstance(AssetType theAssetType, UUID theAssetId, String theInstance) {
554                         this.assetType = theAssetType;
555                         this.assetId = theAssetId;
556                         this.assetInstance = theInstance;
557                         return self();                  
558                 }
559                 
560                 protected String normalizeInstanceName(String theName) {
561                         return StringUtils.removePattern(theName, "[ \\.\\-]+").toLowerCase();
562                 }
563                 
564                 protected String[] mandatoryInfoEntries() {
565                         return ASDC.this.artifactMandatoryEntries;
566                 }
567
568                 protected String ref(UUID theArtifactId) {
569                         return (this.assetInstance == null) ?
570                                                                 refAssetArtifact(this.assetType, this.assetId, theArtifactId) :
571                                                                 refAssetInstanceArtifact(this.assetType, this.assetId, normalizeInstanceName(this.assetInstance), theArtifactId);
572                 }
573         } 
574
575         protected static final String[] uploadMandatoryEntries = new String[] { "artifactName",
576                                                                                                                                                                                                                                                                                                          "artifactType",
577                                                                                                                                                                                                                                                                                                          "artifactGroupType", 
578                                                                                                                                                                                                                                                                                                          "artifactLabel",
579                                                                                                                                                                                                                                                                                                          "description",
580                                                                                                                                                                                                                                                                                                          "payloadData" };
581
582         public class ArtifactUploadAction extends ASDCArtifactAction<ArtifactUploadAction> {
583                 
584                 protected ArtifactUploadAction() {
585                         super(new JSONObject());
586                 }
587
588                 protected ArtifactUploadAction self() {
589                         return this;
590                 }
591                 
592                 public ArtifactUploadAction withContent(byte[] theContent) {
593                         return with("payloadData", Base64Utils.encodeToString(theContent));
594                 }
595
596                 public ArtifactUploadAction withContent(File theFile) throws IOException {
597                         return withContent(FileUtils.readFileToByteArray(theFile));
598                 }
599
600                 public ArtifactUploadAction withLabel(String theLabel) {
601                         return with("artifactLabel", theLabel);
602                 }
603                 
604                 public ArtifactUploadAction withName(String theName) {
605                         return with("artifactName", theName);
606                 }
607                 
608                 public ArtifactUploadAction withDisplayName(String theName) {
609                         return with("artifactDisplayName", theName);
610                 }
611
612                 public ArtifactUploadAction withType(ArtifactType theType) {
613                         return with("artifactType", theType.toString());
614                 }
615
616                 public ArtifactUploadAction withGroupType(ArtifactGroupType theGroupType) {
617                         return with("artifactGroupType", theGroupType.toString());
618                 }
619
620                 public ArtifactUploadAction withDescription(String theDescription) {
621                         return with("description", theDescription);
622                 }
623                 
624                 protected String[] mandatoryInfoEntries() {
625                         return ASDC.this.uploadMandatoryEntries;
626                 }
627
628                 public Future<JSONObject> execute() {
629                         checkMandatory();
630                         return ASDC.this.post(ref(null),
631                                                                                                                 (headers) -> prepareHeaders(headers)
632                                                                                                                                                                         .header("USER_ID", this.operatorId),
633                                                                                                                 this.info);
634                 }
635         }
636
637         protected static final String[] updateMandatoryEntries = new String[] { "artifactName",
638                                                                                                                                                                                                                                                                                                          "artifactType",
639                                                                                                                                                                                                                                                                                                          "artifactGroupType", 
640                                                                                                                                                                                                                                                                                                          "artifactLabel",
641                                                                                                                                                                                                                                                                                                          "description",
642                                                                                                                                                                                                                                                                                                          "payloadData" };
643
644         /**
645          * In its current form the update relies on a previous artifact retrieval. One cannot build an update from scratch.
646          * The label, tye and group type must be submitted but cannot be updated
647          */
648         public class ArtifactUpdateAction extends ASDCArtifactAction<ArtifactUpdateAction> {
649
650                 
651                 protected ArtifactUpdateAction(JSONObject theInfo) {
652                         super(theInfo);
653                 }
654                 
655                 protected ArtifactUpdateAction self() {
656                         return this;
657                 }
658                 
659                 public ArtifactUpdateAction withContent(byte[] theContent) {
660                         return with("payloadData", Base64Utils.encodeToString(theContent));
661                 }
662
663                 public ArtifactUpdateAction withContent(File theFile) throws IOException {
664                         return withContent(FileUtils.readFileToByteArray(theFile));
665                 }
666
667                 public ArtifactUpdateAction withDescription(String theDescription) {
668                         return with("description", theDescription);
669                 }
670                 
671                 public ArtifactUpdateAction withName(String theName) {
672                         return with("artifactName", theName);
673                 }
674                 
675                 protected String[] mandatoryInfoEntries() {
676                         return ASDC.this.updateMandatoryEntries;
677                 }
678
679                 /* The json object originates (normally) from a get so it will have entries we need to cleanup */
680                 protected void cleanupInfoEntries() {
681                         this.info.remove("artifactChecksum");
682                         this.info.remove("artifactUUID");
683                         this.info.remove("artifactVersion");
684                         this.info.remove("artifactURL");
685                         this.info.remove("artifactDescription");
686                 }
687                 
688                 public Future<JSONObject> execute() {
689                         UUID artifactUUID = UUID.fromString(this.info.getString("artifactUUID"));
690                         checkMandatory();
691                         cleanupInfoEntries();
692                         return ASDC.this.post(ref(artifactUUID),
693                                                                                                                 (headers) -> prepareHeaders(headers)
694                                                                                                                                                                         .header("USER_ID", this.operatorId),
695                                                                                                                 this.info);
696                 }
697         }
698
699         public class ArtifactDeleteAction extends ASDCArtifactAction<ArtifactDeleteAction> {
700
701                 private UUID            artifactId;
702                 
703                 protected ArtifactDeleteAction(UUID theArtifactId) {
704                         super(null);
705                         this.artifactId = theArtifactId;
706                 }
707                 
708                 protected ArtifactDeleteAction self() {
709                         return this;
710                 }
711                 
712                 public Future<JSONObject> execute() {
713                         checkMandatory();
714                         return ASDC.this.delete(ref(this.artifactId),
715                                                                                                                   (headers) -> prepareHeaders(headers)
716                                                                                                                                                                         .header("USER_ID", this.operatorId));
717                 }
718         }
719
720
721
722
723         public VFCMTCreateAction createVFCMT() {
724                 return new VFCMTCreateAction();
725         }
726         
727         protected static final String[] vfcmtMandatoryEntries = new String[] { "name",
728                                                                                                                                                                                                                                                                                                  "vendorName",
729                                                                                                                                                                                                                                                                                                  "vendorRelease",
730                                                                                                                                                                                                                                                                                                  "contactId" };
731
732
733         public class VFCMTCreateAction extends ASDCAction<VFCMTCreateAction, JSONObject> {
734
735                 protected VFCMTCreateAction() {
736
737                         super(new JSONObject());
738                         this
739                                 .with("resourceType", "VFCMT")
740                                 .with("category", "Template")
741                                 .with("subcategory", "Monitoring Template")
742                                 .with("icon", "defaulticon");
743                 }
744                 
745                 protected VFCMTCreateAction self() {
746                         return this;
747                 }
748
749                 public VFCMTCreateAction withName(String theName) {
750                         return with("name", theName);
751                 }
752
753                 public VFCMTCreateAction withDescription(String theDescription) {
754                         return with("description", theDescription);
755                 }
756                 
757                 public VFCMTCreateAction withVendorName(String theVendorName) {
758                         return with("vendorName", theVendorName);
759                 }
760                 
761                 public VFCMTCreateAction withVendorRelease(String theVendorRelease) {
762                         return with("vendorRelease", theVendorRelease);
763                 }
764                 
765                 public VFCMTCreateAction withTags(String... theTags) {
766                         for (String tag: theTags)
767                                 this.info.append("tags", tag);
768                         return this;                    
769                 }
770                 
771                 public VFCMTCreateAction withIcon(String theIcon) {
772                         return with("icon", theIcon);
773                 }
774                 
775                 protected String[] mandatoryInfoEntries() {
776                         return ASDC.this.vfcmtMandatoryEntries;
777                 }
778                 
779                 public VFCMTCreateAction withContact(String theContact) {
780                         return with("contactId", theContact);
781                 }
782                 
783                 public Future<JSONObject> execute() {
784                 
785                         this.info.putOnce("contactId", this.operatorId);        
786                         this.info.append("tags", info.optString("name"));
787                         checkMandatory();
788                         return ASDC.this.post(refAssets(AssetType.resource),
789                                                                                                                 (headers) -> prepareHeaders(headers)
790                                                                                                                                                                         .header("USER_ID", this.operatorId),
791                                                                                                                 this.info);
792                 }
793
794         }
795
796         public static JSONObject merge(JSONObject theOriginal, JSONObject thePatch) {
797                 for (String key: (Set<String>)thePatch.keySet()) {
798                         if (!theOriginal.has(key))
799                                 theOriginal.put(key, thePatch.get(key));
800                 }
801                 return theOriginal;
802         }
803
804         protected URI refUri(String theRef) {
805                 try {
806                         return new URI(this.rootUri + theRef);
807                 }
808                 catch(URISyntaxException urisx) {
809                         throw new UncheckedIOException(new IOException(urisx));
810                 }
811         }
812
813         private HttpHeaders prepareHeaders() {
814                 HttpHeaders headers = new HttpHeaders();
815                 headers.add(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes()));
816                 headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
817                 headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE);
818                 headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE);
819                 headers.add("X-ECOMP-InstanceID", this.instanceId);
820
821                 return headers;
822         }
823
824         private RequestEntity.HeadersBuilder prepareHeaders(RequestEntity.HeadersBuilder theBuilder) {
825                 return theBuilder
826                         .header(HttpHeaders.AUTHORIZATION, "Basic " + Base64Utils.encodeToString((this.user + ":" + this.passwd).getBytes()))
827                         .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
828                         .header(HttpHeaders.ACCEPT, MediaType.APPLICATION_OCTET_STREAM_VALUE)
829                         .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
830                         .header("X-ECOMP-InstanceID", this.instanceId);
831         }
832
833         public <T> Future<T> fetch(String theRef, Class<T> theContentType) {
834                 return exchange(theRef, HttpMethod.GET, new HttpEntity(prepareHeaders()), theContentType);
835         }
836
837         public Future<JSONObject> post(String theRef, JSONObject thePost) {
838                 return exchange(theRef, HttpMethod.POST, new HttpEntity<JSONObject>(thePost, prepareHeaders()), JSONObject.class);
839         }
840         
841         public Future<JSONObject> post(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder, JSONObject thePost) {
842                 RequestEntity.BodyBuilder builder = RequestEntity.post(refUri(theRef));
843                 theHeadersBuilder.apply(builder);
844
845                 return exchange(theRef, HttpMethod.POST, builder.body(thePost), JSONObject.class);
846         }
847         
848         public Future<JSONObject> delete(String theRef, UnaryOperator<RequestEntity.HeadersBuilder> theHeadersBuilder) {
849
850                 RequestEntity.HeadersBuilder builder = RequestEntity.delete(refUri(theRef));
851                 theHeadersBuilder.apply(builder);
852
853                 return exchange(theRef, HttpMethod.DELETE, builder.build(), JSONObject.class);
854         }
855         
856         public <T> Future<T> exchange(String theRef, HttpMethod theMethod, HttpEntity theRequest, Class<T> theResponseType) {
857                 
858                 AsyncRestTemplate restTemplate = new AsyncRestTemplate();
859
860                 List<HttpMessageConverter<?>> converters = restTemplate.getMessageConverters();
861                 converters.add(0, new JSONHttpMessageConverter());
862                 restTemplate.setMessageConverters(converters);
863
864                 restTemplate.setInterceptors(Collections.singletonList(new ContentMD5Interceptor()));
865                 ASDCFuture<T> result = new ASDCFuture<T>();
866                 String uri = this.rootUri + theRef;
867                 try {
868                         restTemplate
869                                 .exchange(uri, theMethod, theRequest, theResponseType)
870                                         .addCallback(result.callback);
871                 }
872                 catch (RestClientException rcx) {
873                         errLogger.log(LogLevel.WARN, this.getClass().getName(), "Failed to fetch {} {}", uri, rcx);
874                         return Futures.failedFuture(rcx);
875                 }
876                 catch (Exception x) {
877                         errLogger.log(LogLevel.WARN, this.getClass().getName(), "Failed to fetch {} {}", uri, x);
878                         return Futures.failedFuture(x);
879                 }
880          
881                 return result;
882         }
883
884
885
886         public class ASDCFuture<T>
887                                                                                 extends Futures.BasicFuture<T> {
888
889                 private boolean http404toEmpty = false;
890
891                 ASDCFuture() {
892                 }
893
894                 public ASDCFuture setHttp404ToEmpty(boolean doEmpty) {
895                         this.http404toEmpty = doEmpty;
896                         return this;
897                 }
898
899                 ListenableFutureCallback<ResponseEntity<T>> callback = new ListenableFutureCallback<ResponseEntity<T>>() {
900
901                         public void     onSuccess(ResponseEntity<T> theResult) {
902                                 ASDCFuture.this.result(theResult.getBody());
903                         }
904
905                         public void     onFailure(Throwable theError) {
906                                 if (theError instanceof HttpClientErrorException) {
907                                 //      if (theError.getRawStatusCode() == 404 && this.http404toEmpty)
908                                 //              ASDCFuture.this.result(); //th eresult is of type T ...
909                                 //      else
910                                                 ASDCFuture.this.cause(new ASDCException((HttpClientErrorException)theError));
911                                 }
912                                 else {
913                                         ASDCFuture.this.cause(theError);
914                                 }
915                         }
916                 };
917
918         }
919
920         public class ContentMD5Interceptor implements AsyncClientHttpRequestInterceptor {
921
922     @Override
923     public ListenableFuture<ClientHttpResponse> intercept(
924             HttpRequest theRequest, byte[] theBody, AsyncClientHttpRequestExecution theExecution)
925                                                                                                                                                                                                                                                                                                                 throws IOException {
926                                 if (HttpMethod.POST == theRequest.getMethod()) {
927                 HttpHeaders headers = theRequest.getHeaders();
928               headers.add("Content-MD5", Base64Utils.encodeToString(
929                                                                                                                                                                 //DigestUtils.md5Digest(theBody)));
930                                                                                                                                                                 DigestUtils.md5Hex(theBody).getBytes()));
931                                                                                                                                                                         
932                                 }
933           return theExecution.executeAsync(theRequest, theBody);
934     }
935         }
936
937         public static void main(String[] theArgs) throws Exception {
938
939                 CommandLineParser parser = new BasicParser();
940                 
941                 String user_id = "jh0003";
942                 
943                 Options options = new Options();
944                 options.addOption(OptionBuilder
945                                                                                                                   .withArgName("target")
946                                                                                                                         .withLongOpt("target")
947                                .withDescription("target asdc system")
948                                                                                                                         .hasArg()
949                                                                                                                         .isRequired()
950                                                                                                                         .create('t') );
951                         
952                 options.addOption(OptionBuilder
953                                                                                                                   .withArgName("action")
954                                                                                                                         .withLongOpt("action")
955                               .withDescription("one of: list, get, getartifact, checkin, checkout")
956                                                                                                                         .hasArg()
957                                                                                                                         .isRequired()
958                                                                                                                         .create('a') );
959
960                 options.addOption(OptionBuilder
961                                                                                                                   .withArgName("assetType")
962                                                                                                                         .withLongOpt("assetType")
963                                .withDescription("one of resource, service, product")
964                                                                                                                         .hasArg()
965                                                                                                                         .isRequired()
966                                                                                                                         .create('k') ); //k for 'kind' ..
967
968                 options.addOption(OptionBuilder
969                                                                                                                   .withArgName("assetId")
970                                                                                                                         .withLongOpt("assetId")
971                                .withDescription("asset uuid")
972                                                                                                                         .hasArg()
973                                                                                                                         .create('u') ); //u for 'uuid'
974
975                 options.addOption(OptionBuilder
976                                                                                                                   .withArgName("artifactId")
977                                                                                                                         .withLongOpt("artifactId")
978                                .withDescription("artifact uuid")
979                                                                                                                         .hasArg()
980                                                                                                                         .create('s') ); //s for 'stuff'
981
982                 options.addOption(OptionBuilder
983                                                                                                                   .withArgName("listFilter")
984                                                                                                                         .withLongOpt("listFilter")
985                                .withDescription("filter for list operations")
986                                                                                                                         .hasArg()
987                                                                                                                         .create('f') ); //u for 'uuid'
988
989                 CommandLine line = null;
990                 try {
991                 line = parser.parse(options, theArgs);
992                 }
993                 catch(ParseException exp) {
994                         errLogger.log(LogLevel.ERROR, ASDC.class.getName(), exp.getMessage());
995                         new HelpFormatter().printHelp("asdc", options);
996                         return;
997                 }
998
999                 ASDC asdc = new ASDC();
1000                 asdc.setUri(new URI(line.getOptionValue("target")));
1001
1002                 String action = line.getOptionValue("action");
1003                 if (action.equals("list")) {
1004                         JSONObject filterInfo = new JSONObject(
1005                                                                                                                                                         line.hasOption("listFilter") ?
1006                                                                                                                                                                 line.getOptionValue("listFilter") : "{}");
1007                         JSONArray assets = 
1008                                 asdc.getAssets(ASDC.AssetType.valueOf(line.getOptionValue("assetType")), JSONArray.class,
1009                                                                                          filterInfo.optString("category", null), filterInfo.optString("subCategory", null))
1010                                                 .waitForResult();
1011                         for (int i = 0; i < assets.length(); i++) {
1012                                 debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"> {}", assets.getJSONObject(i).toString(2));
1013                         }
1014                 }
1015                 else if (action.equals("get")) {
1016                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),
1017                                         asdc.getAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
1018                                                                                         UUID.fromString(line.getOptionValue("assetId")),
1019                                                                                         JSONObject.class)
1020                                                 .waitForResult()
1021                                                 .toString(2)
1022                         );
1023                 }
1024                 else if (action.equals("getartifact")) {
1025                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),
1026                                         asdc.getAssetArtifact(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
1027                                                                                                                         UUID.fromString(line.getOptionValue("assetId")),
1028                                                                                                                         UUID.fromString(line.getOptionValue("artifactId")),
1029                                                                                                                         String.class)
1030                                                 .waitForResult()
1031                         );
1032                 }
1033                 else if (action.equals("checkin")) {
1034                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),
1035                                         asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
1036                                                                                                         UUID.fromString(line.getOptionValue("assetId")),
1037                                                                                                         ASDC.LifecycleState.Checkin,
1038                                                                                                         user_id,
1039                                                                                                         "cli op")
1040                                                         .waitForResult()
1041                                                         .toString()
1042                         );
1043                 }
1044                 else if (action.equals("checkout")) {
1045                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),
1046                                         asdc.cycleAsset(ASDC.AssetType.valueOf(line.getOptionValue("assetType")),
1047                                                                                                         UUID.fromString(line.getOptionValue("assetId")),
1048                                                                                                         ASDC.LifecycleState.Checkout,
1049                                                                                                         user_id,
1050                                                                                                         "cli op")
1051                                                         .waitForResult()
1052                                                         .toString()
1053                         );
1054                 }
1055                 else if (action.equals("cleanup")) {
1056                         JSONArray resources = asdc.getResources()
1057                                                                                                                                         .waitForResult();
1058                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"Got {} resources", resources.length());
1059
1060                         // vfcmt cleanup 
1061                         for (int i = 0; i < resources.length(); i++) {
1062
1063                                 JSONObject resource = resources.getJSONObject(i);
1064
1065                                 if (resource.getString("resourceType").equals("VFCMT") &&
1066                                                 resource.getString("name").contains("test")) {
1067
1068                                         debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"undocheckout for {}", resource.getString("uuid"));
1069
1070                                         try {
1071                                                 asdc.cycleAsset(AssetType.resource, UUID.fromString(resource.getString("uuid")), LifecycleState.undocheckout, user_id, null)
1072                                                         .waitForResult();
1073                                         }
1074                                         catch (Exception x) {
1075                                                 debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"** {}", x);
1076                                         }
1077                                 }
1078                         }
1079
1080                 }
1081                 else {
1082                         try {
1083                                 debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),
1084                                         asdc.createVFCMT()
1085                                                         .withName("Clonator")
1086                                                         .withDescription("Clone operation target 06192017")
1087                                                         .withVendorName("CloneInc")
1088                                                         .withVendorRelease("1.0")
1089                                                         .withTags("clone")
1090                                                         .withOperator(user_id)
1091                                                         .execute()
1092                                                         .waitForResult()
1093                                                         .toString()
1094                                 );
1095                         }
1096                         catch(Exception x) {
1097                                 debugLogger.log(LogLevel.DEBUG, ASDC.class.getName(),"Failed to create VFCMT: {}", x);
1098                         }
1099                 }
1100         }
1101 }