Support common-dataservice 2.2.x
[federation.git] / gateway / src / main / java / org / acumos / federation / gateway / adapter / onap / ONAP.java
1 /*-
2  * ===============LICENSE_START=======================================================
3  * Acumos
4  * ===================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property & Tech Mahindra. All rights reserved.
6  * ===================================================================================
7  * This Acumos software file is distributed by AT&T and Tech Mahindra
8  * under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *  
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *  
14  * This file is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ===============LICENSE_END=========================================================
19  */
20
21 package org.acumos.federation.gateway.adapter.onap;
22
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.net.URI;
26 import java.time.Instant;
27 import java.util.Collections;
28 import java.util.Comparator;
29 import java.util.HashMap;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.UUID;
34
35 import javax.annotation.PostConstruct;
36 import javax.annotation.PreDestroy;
37
38 import org.acumos.cds.domain.MLPArtifact;
39 import org.acumos.cds.domain.MLPPeer;
40 import org.acumos.cds.domain.MLPPeerSubscription;
41 import org.acumos.cds.domain.MLPSolution;
42 import org.acumos.cds.domain.MLPSolutionRevision;
43 import org.acumos.federation.gateway.adapter.onap.sdc.ASDC;
44 import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.ArtifactGroupType;
45 import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.ArtifactType;
46 import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.AssetType;
47 import org.acumos.federation.gateway.adapter.onap.sdc.ASDC.LifecycleState;
48 import org.acumos.federation.gateway.adapter.onap.sdc.ASDCException;
49 import org.acumos.federation.gateway.cds.ArtifactTypes;
50 import org.acumos.federation.gateway.common.Clients;
51 import org.acumos.federation.gateway.common.FederationClient;
52 import org.acumos.federation.gateway.event.PeerSubscriptionEvent;
53 import org.acumos.federation.gateway.util.Utils;
54 import org.json.JSONArray;
55 import org.json.JSONException;
56 import org.json.JSONObject;
57 import org.slf4j.Logger;
58 import org.slf4j.LoggerFactory;
59 import org.springframework.beans.factory.BeanInitializationException;
60 import org.springframework.beans.factory.annotation.Autowired;
61 import org.springframework.boot.context.properties.ConfigurationProperties;
62 import org.springframework.context.annotation.Conditional;
63 import org.springframework.context.annotation.Scope;
64 import org.springframework.context.event.EventListener;
65 import org.springframework.core.task.TaskExecutor;
66 import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
67 import org.springframework.stereotype.Component;
68 import org.springframework.util.StreamUtils;
69
70 @Component("onap")
71 @Scope("singleton")
72 @ConfigurationProperties(prefix = "onap")
73 @Conditional(ONAPAdapterCondition.class)
74 public class ONAP {
75
76         private final Logger log = LoggerFactory.getLogger(ONAP.class);
77         private ASDC asdc = new ASDC();
78         private String asdcOperator;
79         private TaskExecutor taskExecutor;
80         private ToscaLab        toscalab = new ToscaLab();
81         @Autowired
82         private Clients clients;
83
84         public ONAP() {
85                 log.debug("ONAP::new");
86         }
87
88         public void setSdcUri(URI theUri) {
89                 this.asdc.setUri(theUri);
90         }
91
92         public void setSdcRootPath(String thePath) {
93                 this.asdc.setRootPath(thePath);
94         }
95
96         public void setSdcOperator(String theUid) {
97                 this.asdcOperator = theUid;
98         }
99
100         @PostConstruct
101         public void initOnap() {
102                 log.trace("initOnap");
103
104                 if (this.asdc.getUri() == null)
105                         throw new BeanInitializationException("Forgot to configure the SDC uri ('onap.sdcUri') ??");
106                 if (this.asdcOperator == null)
107                         throw new BeanInitializationException("Forgot to configure the SDC user ('onap.sdcOperator) ??");
108
109                 this.taskExecutor = new ThreadPoolTaskExecutor();
110                 ((ThreadPoolTaskExecutor) this.taskExecutor).setCorePoolSize(1);
111                 ((ThreadPoolTaskExecutor) this.taskExecutor).setMaxPoolSize(1);
112                 ((ThreadPoolTaskExecutor) this.taskExecutor).setQueueCapacity(25);
113                 ((ThreadPoolTaskExecutor) this.taskExecutor).initialize();
114
115                 // temporary
116                 cleanup();
117
118                 // Done
119                 log.trace("Onap available");
120         }
121
122         @PreDestroy
123         public void cleanupOnap() {
124                 log.trace("Onap destroyed");
125         }
126
127         @EventListener
128         public void handlePeerSubscriptionUpdate(PeerSubscriptionEvent theEvent) {
129                 log.info("received peer subscription update event {}", theEvent);
130                 taskExecutor.execute(new ONAPPushTask(theEvent.getPeer(), theEvent.getSubscription()));
131         }
132
133         public class ONAPPushTask implements Runnable {
134
135                 private MLPPeer peer;
136                 private MLPPeerSubscription sub;
137
138                 public ONAPPushTask(MLPPeer thePeer, MLPPeerSubscription theSub) {
139                         this.peer = thePeer;
140                         this.sub = theSub;
141                 }
142
143                 public void run() {
144
145                         // list with category and subcategory currently used for onap
146                         // more dynamic mapping to come: based on solution information it will provide
147                         // sdc assettype, category and subcategory
148
149                         Map selector = null;
150                         String catalogId = null;
151                         try {
152                                 selector = Utils.jsonStringToMap(this.sub.getSelector());
153                                 catalogId = (String)selector.get("catalogId");
154                         }
155                         catch(Exception x) {
156                                 log.error("Failed to parse selector for subscription {}", this.sub);
157                                 return;
158                         }
159                         Instant lastProcessed = this.sub.getProcessed();
160                         if (lastProcessed != null) {
161                                 selector.put("modified", lastProcessed.getEpochSecond());
162                         }
163                         lastProcessed = Instant.now();
164                         
165                         FederationClient acumosClient = clients.getFederationClient(this.peer.getApiUrl());
166                         if (acumosClient == null) {
167                                 log.error("Failed to get client for peer {}", this.peer);
168                                 return;
169                         }
170
171                         List<MLPSolution> acumosSolutions = null;
172                         try {
173                                 acumosSolutions = (List<MLPSolution>)acumosClient.getSolutions(catalogId).getContent();
174                         }
175                         catch(Exception x) {
176                                 log.error("Processing peer " + this.peer + " subscription " + this.sub.getSubId() + ": getSolutions failed.", x);
177                                 return;
178                         }
179                         log.info("Processing peer {} subscription {}, {} yielded solutions {}", this.peer, this.sub.getSubId(), selector, acumosSolutions);
180
181                         JSONArray sdcAssets = null;
182                         try {
183                                 sdcAssets = asdc.getAssets(AssetType.resource, JSONArray.class, "Generic", "Abstract");
184                         }
185                         catch (Exception x) {
186                                 log.error("Failed to list ONAP SDC assets: " + x.getCause(), x);
187                                 // if this is a 404 NotFound, continue, otherwise, fail
188                                 if (ASDCException.isNotFound(x))
189                                         sdcAssets = new JSONArray();
190                                 else
191                                         return;
192                         }
193                         log.info("Mapping received Acumos solutions \n{}\n to retrieved ONAP SDC assets \n{}",
194                         acumosSolutions, sdcAssets);
195
196                         for (MLPSolution acumosSolution : acumosSolutions) {
197
198                                 List<MLPSolutionRevision> acumosRevisions = null;
199                                 try {
200                                         acumosRevisions = acumosClient
201                                                         .getSolutionRevisions(acumosSolution.getSolutionId()).getContent();
202                                 }
203                                 catch (Exception x) {
204                                         log.error("Failed to retrieve acumos revisions", x);
205                                         return;
206                                 }
207                                 sortAcumosSolutionRevisions(acumosRevisions);
208
209                                 try {
210                                         // does the solution already exist in sdc
211                                         JSONObject sdcAsset = lookupSdcAsset(acumosSolution, sdcAssets);
212                                         if (sdcAsset == null) {
213                                                 // new solution
214                                                 sdcAsset = createSdcAsset(acumosSolution, acumosRevisions.get(acumosRevisions.size()-1));
215                                         }
216                                         else {
217                                                 sdcAsset = updateSdcAsset(sdcAsset, acumosSolution, acumosRevisions);
218                                         }
219                                         updateAssetArtifacts(sdcAsset, acumosSolution, acumosRevisions);
220                                 }
221                                 catch (Exception x) {
222                                         log.error("Mapping of acumos solution failed for: " + acumosSolution + ": " + x);
223                                 }
224                         }
225                 }
226
227                 public JSONObject lookupSdcAsset(MLPSolution theSolution, JSONArray theAssets) {
228                         if (theAssets == null || theAssets.length() == 0)
229                                 return null;
230                         for (int i = 0; i < theAssets.length(); i++) {
231                                 JSONObject asset = theAssets.optJSONObject(i);
232                                 if (sameId(theSolution, asset))
233                                         return asset;
234                         }
235                         return null;
236                 }
237
238                 public JSONObject createSdcAsset(MLPSolution theSolution, MLPSolutionRevision theRevision) throws Exception {
239                         log.info("Creating ONAP SDC VF for solution {}", theSolution);
240
241                         try {
242                                 return ONAP.this.asdc.createVF()
243                                                 .withCategory("Generic")
244                                                 .withSubCategory("Abstract")
245                                                 .withName(theSolution.getName() + "-" + theSolution.getSolutionId()) // sdc names are unique,
246                                                                                                                                                                                                 // acumos ones not so
247                                                 .withDescription(theSolution.getTags().toString()) //the actual description has moved and is too large to fit in here
248                                                 .withVendorName("Acumos")
249                                                 .withVendorRelease(theRevision.getVersion()) //is this meaningful ? given that it cannot be updated ..
250                                                 .withTags("acumos", theSolution.getSolutionId()) // can I fit an UUID as tag ??
251                                                 .withOperator(ONAP.this.asdcOperator/* theSolution.getOwnerId() */) // probably won't work, SDC
252                                                 // expects a user uuid
253                                                 .get();
254                         }
255                         catch (Exception x) {
256                                 log.error("Failed to create ONAP SDC VF", x);
257                                 throw x;
258                         }
259                 }
260
261                 /**
262                  * There is no such thing as updating an asset in the ASDC REST API, we can only
263                  * update the artifacts ..
264                  * 
265                  * @param theAssetInfo
266                  *            Asset info
267                  * @param theSolution
268                  *            solution
269                  * @param theRevisions revision
270                  * @return SDC Asset info
271                  */
272                 public JSONObject updateSdcAsset(JSONObject theAssetInfo, MLPSolution theSolution, List<MLPSolutionRevision> theRevisions) {
273                         log.info("Updating ONAP SDC VF {} for Acumos solution {}", theAssetInfo.optString("uuid"), theSolution);
274                         return theAssetInfo;
275                 }
276
277                 public void updateAssetArtifacts(JSONObject theAssetInfo, MLPSolution theSolution, List<MLPSolutionRevision> theRevisions)
278                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 throws Exception {
279                         try {
280                                 theAssetInfo = ONAP.this.asdc
281                                                 .getAsset(AssetType.resource, UUID.fromString(theAssetInfo.getString("uuid")), JSONObject.class);
282                         }
283                         catch (Exception x) {
284                                 log.error("Failed to retrieve ONAP SDC asset metadata for " + theAssetInfo.getString("uuid") + " : " + x);
285                                 throw x;
286                         }
287
288                         JSONArray sdcArtifacts = theAssetInfo.optJSONArray("artifacts");
289                         if (sdcArtifacts == null) {
290                                 sdcArtifacts = new JSONArray();
291                         }
292
293                         //we could have a new model, a new model revision or updates to the currently mapped revision's artifacts.
294                         //currently we always fast-forward to the latest revision available in acumos
295                         MLPSolutionRevision mappedAcumosRevision = theRevisions.get(theRevisions.size() - 1);
296
297                         List<MLPArtifact> acumosArtifacts = null;
298                         try {
299                                 acumosArtifacts = clients.getFederationClient(this.peer.getApiUrl())
300                                         .getArtifacts(theSolution.getSolutionId(), mappedAcumosRevision.getRevisionId())
301                                                 .getContent();
302                         }
303                         catch (Exception x) {
304                                 log.error("Failed to retrieve acumos artifacts" + x);
305                                 throw x;
306                         }
307
308                         if (acumosArtifacts == null)
309                                 acumosArtifacts = new LinkedList<>();
310
311                         //add an artifact to be mapped for revision tracking purposes
312                         {
313                                 MLPArtifact mapper = new MLPArtifact(mappedAcumosRevision.getVersion(),
314                                                                                                                                 ArtifactTypes.Metadata.getCode(),
315                                                                                                                                 "mapper",
316                                                                                                                                 null,
317                                                                                                                                 "", //owner: never sees CDS so irrelevant 
318                                                                                                                                 0);
319                                 mapper.setArtifactId("0");//a unique value among the other artifacts of this revision
320                                 acumosArtifacts.add(mapper);
321                         }
322
323                         // all this could be better writen but the 2 sets are expected to be small so we
324                         // favor readability
325
326                         //!! we support a 1-to-n mapping of artifacts from Acumos to SDC
327
328                         // acumos artifacts that do not exist locally need to be added
329                         List<MLPArtifact> newArtifacts = new LinkedList<>();
330                         Map<MLPArtifact, JSONArray> updatedArtifacts = new HashMap<>();
331
332                         log.info("Acumos artifacts: {}", acumosArtifacts);
333                         log.info("SDC artifacts: {}", sdcArtifacts);
334
335                         for (MLPArtifact acumosArtifact : acumosArtifacts) {
336                                 JSONArray sdcMappedArtifacts = new JSONArray();
337                                 for (int i = 0; i < sdcArtifacts.length(); i++) {
338                                         JSONObject sdcArtifact = sdcArtifacts.getJSONObject(i);
339                                         if (sameId(acumosArtifact, sdcArtifact)) {
340                                                 sdcMappedArtifacts.put(sdcArtifact);
341                                         }
342                                 }
343
344                                 if (sdcMappedArtifacts.length() > 0) {
345                                         //sdc artifacts mapped to the acumos artifacts were found
346                                         //if not at the same version, update
347                                         //TODO: add a coherence check to make sure all sdcArtifacts are at the same (acumos) version
348                                         if (!sameVersion(acumosArtifact, sdcMappedArtifacts.getJSONObject(0))) {
349                                                 updatedArtifacts.put(acumosArtifact, sdcMappedArtifacts);
350                                         }
351                                 }
352                                 else {
353                                         newArtifacts.add(acumosArtifact);
354                                 }
355                         }
356
357                         log.info("New artifacts: {}", newArtifacts);
358                         for (MLPArtifact acumosArtifact : newArtifacts) {
359                                 try {
360                                         for (ASDC.ArtifactUploadAction uploadAction:
361                                                                 mapNewArtifact(theAssetInfo, theSolution.getSolutionId(), mappedAcumosRevision.getRevisionId(),
362                                                                                                                          acumosArtifact)) {
363                                                 uploadAction.get();
364                                         }
365                                 }
366                                 catch (Exception x) {
367                                         log.error("Failed to create ONAP SDC VF Artifacts for " + acumosArtifact, x);
368                                 }
369                         }
370
371                         log.warn("Updated SDC artifacts: {}", updatedArtifacts.keySet());
372                         for (Map.Entry<MLPArtifact, JSONArray> updateEntry : updatedArtifacts.entrySet()) {
373                                 MLPArtifact acumosArtifact = updateEntry.getKey();
374                                 try {
375                                         for (ASDC.ArtifactUpdateAction updateAction: 
376                                                                 mapArtifact(theAssetInfo, theSolution.getSolutionId(), mappedAcumosRevision.getRevisionId(),
377                                                                                                                 updateEntry.getKey(), updateEntry.getValue())) {
378                                                 updateAction.get();
379                                         }
380                                 }
381                                 catch (Exception x) {
382                                         log.error("Failed to update ONAP SDC VF Artifact for " + updateEntry.getKey(), x);
383                                 }
384                         }
385
386                         // sdc artifacts that do not have a acumos counterpart should be deleted (if
387                         // they are labeled as having
388                         // originated in acumos).
389                         List<JSONObject> deletedArtifacts = new LinkedList<>();
390                         for (int i = 0; i < sdcArtifacts.length(); i++) {
391                                 JSONObject sdcArtifact = sdcArtifacts.getJSONObject(i);
392                                 boolean found = false;
393                                 for (MLPArtifact acumosArtifact : acumosArtifacts) {
394                                         if (sameId(acumosArtifact, sdcArtifact)) {
395                                                 found = true;
396                                                 break;
397                                         }
398                                 }
399                                 if (!found && isAcumosOriginated(sdcArtifact)) {
400                                         deletedArtifacts.add(sdcArtifact);
401                                 }
402                         }
403                         log.warn("Deleted SDC artifacts: {}", deletedArtifacts);
404                         for (JSONObject sdcArtifact : deletedArtifacts) {
405                                 try {
406                                         asdc.deleteAssetArtifact(AssetType.resource, UUID.fromString(theAssetInfo.getString("uuid")),
407                                                         UUID.fromString(sdcArtifact.getString("artifactUUID"))).withOperator(ONAP.this.asdcOperator)
408                                                         .get();
409                                 }
410                                 catch (Exception x) {
411                                         log.error("Failed to delete ONAP SDC VF Artifact", x);
412                                 }
413                         }
414                 }
415
416                 /**
417                  */
418                 private List<ASDC.ArtifactUploadAction> mapNewArtifact(
419                         JSONObject theSDCAsset,
420                         String theAcumosSolutionId, String theAcumosRevisionId, MLPArtifact theAcumosArtifact) {
421
422                         if (isDCAEComponentSpecification(theAcumosArtifact)) {
423
424                                 byte[] content = null;
425                                 try {
426                                         content = retrieveContent(theAcumosSolutionId, theAcumosRevisionId, theAcumosArtifact);
427                                 }
428                                 catch (Exception x) {
429                                         log.error("Failed to retrieve Acumoms artifact content from " + theAcumosArtifact.getUri(), x);
430                                         return Collections.emptyList();
431                                 }
432
433                                 JSONObject models = null;
434                                 try {
435                                         models = new JSONObject(toscalab.create_model(new ByteArrayInputStream(content)));
436                                 }
437                                 catch (JSONException jsonx) {
438                                         log.error("Failed to parse toscalab output", jsonx);
439                                         return Collections.emptyList();
440                                 }
441                                 catch (Exception x) {
442                                         log.error("Failed to process DCAE component specification from " + theAcumosArtifact, x);
443                                         return Collections.emptyList();
444                                 }
445
446                                 List<ASDC.ArtifactUploadAction> actions = new LinkedList<>();
447                                 for (String model: models.keySet()) {
448                                         actions.add(
449                                                 asdc.createAssetArtifact(AssetType.resource, UUID.fromString(theSDCAsset.getString("uuid")))
450                                                 .withOperator(ONAP.this.asdcOperator)
451                                                 .withEncodedContent(models.getString(model))
452                                                 .withLabel(theAcumosArtifact.getArtifactTypeCode())
453                                                 .withName(model/*theAcumosArtifact.getName()*/)
454                                                 .withDisplayName(theAcumosArtifact.getMetadata())
455                                                 .withType(ArtifactType.DCAE_TOSCA/*ArtifactType.OTHER*/)
456                                                 .withGroupType(ArtifactGroupType.DEPLOYMENT)
457                                                 .withDescription(theAcumosArtifact.getArtifactId() + "@" + theAcumosArtifact.getVersion())
458                                         );
459                                 }
460                                 return actions;
461                         }
462                         else if (isMapper(theAcumosArtifact)) {
463                                 return Collections.singletonList(
464                                         asdc.createAssetArtifact(AssetType.resource, UUID.fromString(theSDCAsset.getString("uuid")))
465                                                 .withOperator(ONAP.this.asdcOperator)
466                                                 .withContent("{}".getBytes())
467                                                 .withLabel(theAcumosArtifact.getArtifactTypeCode())
468                                                 .withName(theAcumosArtifact.getName())
469                                                 .withDisplayName("mapper")
470                                                 .withType(ArtifactType.OTHER)
471                                                 .withGroupType(ArtifactGroupType.DEPLOYMENT)
472                                                 .withDescription(theAcumosArtifact.getArtifactId() + "@" + theAcumosArtifact.getVersion())
473                                 );
474                         } 
475                         else {
476                                 //everything else gets ignored at this point
477                                 return Collections.emptyList();
478                         }
479                 }
480                 
481                 private List<ASDC.ArtifactUpdateAction> mapArtifact(
482                         JSONObject theSDCAsset, String theAcumosSolutionId, String theAcumosRevisionId,
483                         MLPArtifact theAcumosArtifact, JSONArray theSDCArtifacts) {
484                         
485                         if (isDCAEComponentSpecification(theAcumosArtifact)) {
486                                 byte[] content = null;
487                                 try {
488                                         content = retrieveContent(theAcumosSolutionId, theAcumosRevisionId, theAcumosArtifact);
489                                 }
490                                 catch (Exception x) {
491                                         log.error("Failed to retrieve Acumoms artifact content from " + theAcumosArtifact.getUri(), x);
492                                         return Collections.emptyList();
493                                 }
494
495                                 JSONObject models = null;
496                                 try {
497                                         models = new JSONObject(toscalab.create_model(new ByteArrayInputStream(content)));
498                                 }
499                                 catch (JSONException jsonx) {
500                                         log.error("Failed to parse toscalab output", jsonx);
501                                         return Collections.emptyList();
502                                 }
503                                 catch (Exception x) {
504                                         log.error("Failed to process DCAE component specification from " + theAcumosArtifact, x);
505                                         return Collections.emptyList();
506                                 }
507
508                                 List<ASDC.ArtifactUpdateAction> actions = new LinkedList<>();
509                                 for (int i = 0; i < theSDCArtifacts.length(); i++) {
510                                         JSONObject sdcArtifact = theSDCArtifacts.getJSONObject(i);
511                                         actions.add(
512                                                 asdc.updateAssetArtifact(AssetType.resource, UUID.fromString(theSDCAsset.getString("uuid")), sdcArtifact)
513                                                         .withOperator(ONAP.this.asdcOperator)
514                                                         .withEncodedContent(models.getString(sdcArtifact.getString("name")))
515                                                         .withName(sdcArtifact.getString("name"))
516                                                         .withDescription(theAcumosArtifact.getArtifactId() + "@"        + theAcumosArtifact.getVersion())
517                                         );
518                                 }
519                                 return actions;
520                         }
521                         else if (isMapper(theAcumosArtifact)) {
522                                 if (theSDCArtifacts.length() != 1)
523                                         log.warn("Found more than one mapper artifact {}", theSDCArtifacts);
524                                 return Collections.singletonList(
525                                                 asdc.updateAssetArtifact(AssetType.resource, UUID.fromString(theSDCAsset.getString("uuid")), theSDCArtifacts.getJSONObject(0))
526                                                         .withOperator(ONAP.this.asdcOperator)
527                                                         .withName(theAcumosArtifact.getName())
528                                                         .withDescription(theAcumosArtifact.getArtifactId() + "@"        + theAcumosArtifact.getVersion()));
529                         } 
530                         else {
531                                 log.error("Found sdc artifacts for mlp artifact we do not process {}: {} ", theAcumosArtifact, theSDCArtifacts);
532                                 return Collections.emptyList();
533                         }
534                 }
535
536                 private boolean isDCAEComponentSpecification(MLPArtifact theArtifact) {
537                         return theArtifact.getName().equals("component-specification.json");
538                 }
539                 
540                 private boolean isMapper(MLPArtifact theArtifact) {
541                         return theArtifact.getName().equals("mapper");
542                 }
543
544                 private boolean sameId(MLPSolution theAcumosSolution, JSONObject theSDCAsset) {
545
546                         return theSDCAsset.optString("name", "")
547                                         .equals(theAcumosSolution.getName() + "-" + theAcumosSolution.getSolutionId());
548                 }
549
550                 private boolean sameId(MLPArtifact theAcumosArtifact, JSONObject theSDCArtifact) {
551                         return acumosArtifactId(theSDCArtifact).equals(theAcumosArtifact.getArtifactId());
552                 }
553
554                 /*
555                  * Only safe to call if 'same' returned true
556                  */
557                 private boolean sameVersion(MLPArtifact theAcumosArtifact, JSONObject theSDCArtifact) {
558                         return acumosArtifactVersion(theSDCArtifact).equals(theAcumosArtifact.getVersion());
559                 }
560
561                 private String acumosArtifactId(JSONObject theSDCArtifact) {
562                         return theSDCArtifact.optString("artifactDescription","@").split("@")[0];
563                 }
564
565                 private String acumosArtifactVersion(JSONObject theSDCArtifact) {
566                         return theSDCArtifact.optString("artifactDescription","@").split("@")[1];
567                 }
568
569                 private boolean isAcumosOriginated(JSONObject theSDCArtifact) {
570                         boolean isAcumos = theSDCArtifact.optString("artifactType").equals(ArtifactType.OTHER.toString())
571                                         && theSDCArtifact.optString("artifactGroupType").equals(ArtifactGroupType.DEPLOYMENT.toString());
572                         String[] parts = theSDCArtifact.optString("artifactDescription", "@").split("@");
573                         isAcumos &= (parts.length == 2); // and the first part can be parsed as an UUID
574                         return isAcumos;
575                 }
576
577                 private byte[] retrieveContent(
578                         String theAcumosSolutionId, String theAcumosRevisionId, MLPArtifact theAcumosArtifact)
579                                                                                                                                                                                                                                                                                                                                                         throws Exception {
580                         if (this.peer.isLocal()) {
581                                 return clients.getNexusClient().getForObject(theAcumosArtifact.getUri(), byte[].class);
582                         }
583                         else { //non-local peer
584                                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
585                                 StreamUtils.copy(
586                                         clients.getFederationClient(this.peer.getApiUrl())
587                                                 .getArtifactContent(theAcumosArtifact.getArtifactId())
588                                                         .getInputStream(),
589                                         bos);
590                                 return bos.toByteArray();
591                         }
592                 }
593         }
594
595
596         /**
597          * Removes all (non-commited) Acumos solutions imported into ONAP SDC
598          */
599         protected void cleanup() {
600
601                 JSONArray sdcAssets = null;
602                 try {
603                         sdcAssets = asdc.getAssets(AssetType.resource, JSONArray.class, "Generic", "Abstract");
604                 } catch (Throwable x) {
605                         log.info("Cleanup failed to list ONAP SDC assets: " + x.getCause(), x);
606                 }
607
608                 if (sdcAssets == null)
609                         return;
610
611                 for (int i = 0; i < sdcAssets.length(); i++) {
612                         JSONObject sdcAsset = sdcAssets.optJSONObject(i);
613                         String state = sdcAsset.optString("lifecycleState");
614                         if (state != null && "NOT_CERTIFIED_CHECKEOUT".equals(state)) {
615                                 try {
616                                         asdc.cycleAsset(AssetType.resource, UUID.fromString(sdcAsset.getString("uuid")),
617                                                         LifecycleState.undocheckout, ONAP.this.asdcOperator, null);
618                                 }
619                                 catch (Exception x) {
620                                         log.error("Cleanup ONAP SDC asset: " + sdcAsset.optString("uuid"), x);
621                                 }
622                         }
623                 }
624
625         }
626         
627         /** */
628         private void sortAcumosSolutionRevisions(List<MLPSolutionRevision> theRevisions) {
629
630                 Collections.sort(theRevisions,
631                                                                                  new Comparator<MLPSolutionRevision>() {
632                                                                                         @Override
633                                                                                         public int compare(MLPSolutionRevision theFirst, MLPSolutionRevision theSecond) {
634                                                                                                 return String.CASE_INSENSITIVE_ORDER.compare(theFirst.getVersion(), theSecond.getVersion());
635                                                                                         }
636                                                                                  });
637                                                                                 
638         }
639 }