Prevent race conditions on same distributionId.
[so.git] / asdc-controller / src / main / java / org / onap / so / asdc / client / ASDCController.java
1 /*-
2 d * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7  * ================================================================================
8  * Licensed 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  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.so.asdc.client;
23
24
25 import java.io.File;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.UnsupportedEncodingException;
29 import java.nio.file.Paths;
30 import java.util.List;
31 import java.util.Optional;
32
33 import org.hibernate.StaleObjectStateException;
34 import org.onap.sdc.api.IDistributionClient;
35 import org.onap.sdc.api.consumer.IDistributionStatusMessage;
36 import org.onap.sdc.api.consumer.IFinalDistrStatusMessage;
37 import org.onap.sdc.api.notification.IArtifactInfo;
38 import org.onap.sdc.api.notification.INotificationData;
39 import org.onap.sdc.api.notification.IResourceInstance;
40 import org.onap.sdc.api.results.IDistributionClientDownloadResult;
41 import org.onap.sdc.api.results.IDistributionClientResult;
42 import org.onap.sdc.impl.DistributionClientFactory;
43 import org.onap.sdc.utils.DistributionActionResultEnum;
44 import org.onap.sdc.utils.DistributionStatusEnum;
45 import org.onap.so.asdc.client.exceptions.ASDCControllerException;
46 import org.onap.so.asdc.client.exceptions.ASDCDownloadException;
47 import org.onap.so.asdc.client.exceptions.ASDCParametersException;
48 import org.onap.so.asdc.client.exceptions.ArtifactInstallerException;
49 import org.onap.so.asdc.installer.IVfResourceInstaller;
50 import org.onap.so.asdc.installer.ToscaResourceStructure;
51 import org.onap.so.asdc.installer.VfResourceStructure;
52 import org.onap.so.asdc.installer.bpmn.BpmnInstaller;
53 import org.onap.so.asdc.installer.heat.ToscaResourceInstaller;
54 import org.onap.so.asdc.tenantIsolation.DistributionStatus;
55 import org.onap.so.asdc.tenantIsolation.WatchdogDistribution;
56 import org.onap.so.asdc.util.ASDCNotificationLogging;
57 import org.onap.so.db.request.beans.WatchdogDistributionStatus;
58 import org.onap.so.db.request.data.repository.WatchdogDistributionStatusRepository;
59 import org.onap.so.logger.MessageEnum;
60 import org.onap.so.logger.MsoLogger;
61 import org.springframework.beans.factory.annotation.Autowired;
62 import org.springframework.orm.ObjectOptimisticLockingFailureException;
63 import org.springframework.stereotype.Component;
64
65 import com.fasterxml.jackson.annotation.JsonInclude.Include;
66 import com.fasterxml.jackson.core.JsonProcessingException;
67 import com.fasterxml.jackson.databind.DeserializationFeature;
68 import com.fasterxml.jackson.databind.MapperFeature;
69 import com.fasterxml.jackson.databind.ObjectMapper;
70
71 @Component
72 public class ASDCController {
73
74     protected static final MsoLogger LOGGER = MsoLogger.getMsoLogger (MsoLogger.Catalog.ASDC,ASDCController.class);
75
76
77
78     protected boolean isAsdcClientAutoManaged = false;
79
80     protected String controllerName;
81     
82     private ASDCControllerStatus controllerStatus = ASDCControllerStatus.STOPPED;
83     
84     protected int nbOfNotificationsOngoing = 0;
85
86     @Autowired
87     private ToscaResourceInstaller toscaInstaller;
88     
89     @Autowired
90     private BpmnInstaller bpmnInstaller;
91     
92     @Autowired
93     private WatchdogDistributionStatusRepository wdsRepo;
94     
95     @Autowired
96     private ASDCConfiguration asdcConfig;
97     
98     @Autowired
99     private ASDCStatusCallBack asdcStatusCallBack;
100     
101     @Autowired
102     private ASDCNotificationCallBack asdcNotificationCallBack;
103     
104     private IDistributionClient distributionClient;
105     
106     private static final String UUID_PARAM = "(UUID:";
107     
108     @Autowired
109     private WatchdogDistribution wd;
110    
111
112     public int getNbOfNotificationsOngoing () {
113         return nbOfNotificationsOngoing;
114     }    
115
116     public IDistributionClient getDistributionClient() {
117                 return distributionClient;
118         }
119
120
121
122         public void setDistributionClient(IDistributionClient distributionClient) {
123                 this.distributionClient = distributionClient;
124         }
125
126
127
128         protected void changeControllerStatus (ASDCControllerStatus newControllerStatus) {
129         switch (newControllerStatus) {
130
131             case BUSY:
132                 ++this.nbOfNotificationsOngoing;
133                 this.controllerStatus = newControllerStatus;
134                 break;
135
136             case IDLE:
137                 if (this.nbOfNotificationsOngoing > 1) {
138                     --this.nbOfNotificationsOngoing;
139                 } else {
140                     this.nbOfNotificationsOngoing = 0;
141                     this.controllerStatus = newControllerStatus;
142                 }
143
144                 break;
145             default:
146                 this.controllerStatus = newControllerStatus;
147                 break;
148
149         }
150     }
151
152     public ASDCControllerStatus getControllerStatus () {
153         return this.controllerStatus;
154     }
155     
156     public ASDCController () {
157         isAsdcClientAutoManaged = true;        
158     }
159
160     public ASDCController (String controllerConfigName) {
161         isAsdcClientAutoManaged = true;
162         this.controllerName = controllerConfigName;
163     }
164
165     public ASDCController (String controllerConfigName, IDistributionClient asdcClient, IVfResourceInstaller resourceinstaller) {
166         distributionClient = asdcClient;       
167     }
168
169     public ASDCController (String controllerConfigName,IDistributionClient asdcClient) {
170         distributionClient = asdcClient;
171         this.controllerName = controllerConfigName;     
172     }
173     public String getControllerName() {
174                 return controllerName;
175         }
176
177         public void setControllerName(String controllerName) {
178                 this.controllerName = controllerName;
179         }
180
181         /**
182      * This method initializes the ASDC Controller and the ASDC Client.
183      *
184      * @throws ASDCControllerException It throws an exception if the ASDC Client cannot be instantiated or if an init
185      *         attempt is done when already initialized
186      * @throws ASDCParametersException If there is an issue with the parameters provided
187      * @throws IOException In case of issues when trying to load the key file
188      */
189     public void initASDC () throws ASDCControllerException {
190         String event = "Initialize the ASDC Controller";
191         MsoLogger.setServiceName ("InitASDC");
192         LOGGER.debug (event);
193         if (this.getControllerStatus () != ASDCControllerStatus.STOPPED) {
194             String endEvent = "The controller is already initialized, call the closeASDC method first";
195             throw new ASDCControllerException (endEvent);
196         }
197
198         if (asdcConfig != null) {          
199             asdcConfig.setAsdcControllerName(controllerName);
200         }    
201
202         if (this.distributionClient == null) {
203             distributionClient = DistributionClientFactory.createDistributionClient ();
204         }
205         
206         long initStartTime = System.currentTimeMillis ();
207         IDistributionClientResult result = this.distributionClient.init (asdcConfig,
208                                                                          asdcNotificationCallBack, asdcStatusCallBack);
209         if (!result.getDistributionActionResult ().equals (DistributionActionResultEnum.SUCCESS)) {
210             String endEvent = "ASDC distribution client init failed with reason:"
211                               + result.getDistributionMessageResult ();
212             LOGGER.recordMetricEvent (initStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, "Initialization of the ASDC Controller failed with reason:" + result.getDistributionMessageResult (), "ASDC", "init", null);
213             LOGGER.debug (endEvent);
214             this.changeControllerStatus (ASDCControllerStatus.STOPPED);
215             throw new ASDCControllerException ("Initialization of the ASDC Controller failed with reason: "
216                                                + result.getDistributionMessageResult ());
217         }
218         LOGGER.recordMetricEvent (initStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully initialize ASDC Controller", "ASDC", "init", null);
219
220         long clientstartStartTime = System.currentTimeMillis ();
221         result = this.distributionClient.start ();
222         if (!result.getDistributionActionResult ().equals (DistributionActionResultEnum.SUCCESS)) {
223             String endEvent = "ASDC distribution client start failed with reason:"
224                               + result.getDistributionMessageResult ();
225             LOGGER.recordMetricEvent (clientstartStartTime, MsoLogger.StatusCode.ERROR, MsoLogger.ResponseCode.UnknownError, endEvent, "ASDC", "start", null);
226             LOGGER.debug (endEvent);           
227             this.changeControllerStatus (ASDCControllerStatus.STOPPED);
228             throw new ASDCControllerException ("Startup of the ASDC Controller failed with reason: "
229                                                + result.getDistributionMessageResult ());
230         }
231         LOGGER.recordMetricEvent (clientstartStartTime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully start ASDC distribution client", "ASDC", "start", null);
232
233
234         this.changeControllerStatus (ASDCControllerStatus.IDLE);
235         LOGGER.info (MessageEnum.ASDC_INIT_ASDC_CLIENT_SUC, "ASDC", "changeControllerStatus","");
236     }
237
238     /**
239      * This method closes the ASDC Controller and the ASDC Client.
240      *
241      * @throws ASDCControllerException It throws an exception if the ASDC Client cannot be closed because
242      *         it's currently BUSY in processing notifications.
243      */
244     public void closeASDC () throws ASDCControllerException {
245
246         MsoLogger.setServiceName ("CloseController");
247         if (this.getControllerStatus () == ASDCControllerStatus.BUSY) {
248             throw new ASDCControllerException ("Cannot close the ASDC controller as it's currently in BUSY state");
249         }
250         if (this.distributionClient != null) {
251             this.distributionClient.stop ();
252             // If auto managed we can set it to Null, ASDCController controls it.
253             // In the other case the client of this class has specified it, so we can't reset it
254             if (isAsdcClientAutoManaged) {
255                 // Next init will initialize it with a new ASDC Client
256                 this.distributionClient = null;
257             }
258
259         }
260         this.changeControllerStatus (ASDCControllerStatus.STOPPED);
261     }
262
263     private boolean checkResourceAlreadyDeployed (VfResourceStructure resource) throws ArtifactInstallerException {
264
265         
266                 if (toscaInstaller.isResourceAlreadyDeployed (resource)) {
267                         LOGGER.info (MessageEnum.ASDC_ARTIFACT_ALREADY_EXIST,
268                     resource.getResourceInstance().getResourceInstanceName(),
269                     resource.getResourceInstance().getResourceUUID(),
270                     resource.getResourceInstance().getResourceName(), "", "");
271
272                         this.sendDeployNotificationsForResource(resource,DistributionStatusEnum.ALREADY_DOWNLOADED,null);
273                         this.sendDeployNotificationsForResource(resource,DistributionStatusEnum.ALREADY_DEPLOYED,null);
274
275                 return true;
276         } else {
277                 return false;
278         }
279     }
280
281    
282
283     protected IDistributionClientDownloadResult downloadTheArtifact (IArtifactInfo artifact,
284                                                                    String distributionId) throws ASDCDownloadException {
285
286         LOGGER.debug ("Trying to download the artifact : " + artifact.getArtifactURL ()
287                       + UUID_PARAM
288                       + artifact.getArtifactUUID ()
289                       + ")");
290         IDistributionClientDownloadResult downloadResult;
291
292
293         try {
294             downloadResult = distributionClient.download (artifact);
295             if (null == downloadResult) {
296                 LOGGER.info (MessageEnum.ASDC_ARTIFACT_NULL, artifact.getArtifactUUID (), "", "");
297                 return downloadResult;
298             }
299         } catch (RuntimeException e) {
300             LOGGER.debug ("Not able to download the artifact due to an exception: " + artifact.getArtifactURL ());
301             this.sendASDCNotification (NotificationType.DOWNLOAD,
302                                        artifact.getArtifactURL (),
303                                        asdcConfig.getConsumerID (),
304                                        distributionId,
305                                        DistributionStatusEnum.DOWNLOAD_ERROR,
306                                        e.getMessage (),
307                                        System.currentTimeMillis ());
308
309             throw new ASDCDownloadException ("Exception caught when downloading the artifact", e);
310         }
311
312         if (DistributionActionResultEnum.SUCCESS.equals(downloadResult.getDistributionActionResult ())) {
313
314             LOGGER.info (MessageEnum.ASDC_ARTIFACT_DOWNLOAD_SUC,
315                          artifact.getArtifactURL (),
316                          artifact.getArtifactUUID (),
317                          String.valueOf (downloadResult.getArtifactPayload ().length), "", "");
318
319         } else {
320
321             LOGGER.error (MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL,
322                           artifact.getArtifactName (),
323                           artifact.getArtifactURL (),
324                           artifact.getArtifactUUID (),
325                           downloadResult.getDistributionMessageResult (), "", "", MsoLogger.ErrorCode.DataError, "ASDC artifact download fail");
326
327             this.sendASDCNotification (NotificationType.DOWNLOAD,
328                                        artifact.getArtifactURL (),
329                                        asdcConfig.getConsumerID (),
330                                        distributionId,
331                                        DistributionStatusEnum.DOWNLOAD_ERROR,
332                                        downloadResult.getDistributionMessageResult (),
333                                        System.currentTimeMillis ());
334
335             throw new ASDCDownloadException ("Artifact " + artifact.getArtifactName ()
336                                              + " could not be downloaded from ASDC URL "
337                                              + artifact.getArtifactURL ()
338                                              + UUID_PARAM
339                                              + artifact.getArtifactUUID ()
340                                              + ")"
341                                              + System.lineSeparator ()
342                                              + "Error message is "
343                                              + downloadResult.getDistributionMessageResult ()
344                                              + System.lineSeparator ());
345
346         }
347
348         this.sendASDCNotification (NotificationType.DOWNLOAD,
349                                    artifact.getArtifactURL (),
350                                    asdcConfig.getConsumerID (),
351                                    distributionId,
352                                    DistributionStatusEnum.DOWNLOAD_OK,
353                                    null,
354                                    System.currentTimeMillis ());
355         return downloadResult;
356
357     }
358
359     private void writeArtifactToFile (IArtifactInfo artifact,
360                 IDistributionClientDownloadResult resultArtifact) {
361
362         LOGGER.debug ("Trying to write artifact to file : " + artifact.getArtifactURL ()
363                         + UUID_PARAM
364                         + artifact.getArtifactUUID ()
365                         + ")");
366         
367         String filePath = Paths.get(System.getProperty("mso.config.path"), "ASDC",  artifact.getArtifactVersion(), artifact.getArtifactName()).normalize().toString();
368         // make parent directory
369         File file = new File(filePath);         
370         File fileParent = file.getParentFile();
371         if (!fileParent.exists()) {
372             fileParent.mkdirs();
373         }
374
375         byte[] payloadBytes = resultArtifact.getArtifactPayload();
376         
377         try (FileOutputStream outFile = new FileOutputStream(filePath)) {
378                 LOGGER.info(MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF, "***WRITE FILE ARTIFACT NAME", "ASDC", artifact.getArtifactName());
379                 outFile.write(payloadBytes, 0, payloadBytes.length);
380                 outFile.close();
381         } catch (Exception e) { 
382                         LOGGER.debug("Exception :",e);
383             LOGGER.error(MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL,
384                                 artifact.getArtifactName (),
385                                 artifact.getArtifactURL (),
386                                 artifact.getArtifactUUID (),
387                                 resultArtifact.getDistributionMessageResult (), "", "", MsoLogger.ErrorCode.DataError, "ASDC write to file failed"); 
388         } 
389         
390     }
391
392
393     protected void sendDeployNotificationsForResource(VfResourceStructure vfResourceStructure,DistributionStatusEnum distribStatus, String errorReason) {
394
395         for (IArtifactInfo artifactInfo : vfResourceStructure.getResourceInstance().getArtifacts()) {
396
397                 if ((DistributionStatusEnum.DEPLOY_OK.equals(distribStatus) && !artifactInfo.getArtifactType().equalsIgnoreCase("OTHER") && !vfResourceStructure.isAlreadyDeployed())
398                                 // This could be NULL if the artifact is a VF module artifact, this won't be present in the MAP
399                                 && vfResourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID()) != null
400                                 && vfResourceStructure.getArtifactsMapByUUID().get(artifactInfo.getArtifactUUID()).getDeployedInDb() == 0) {
401                         this.sendASDCNotification (NotificationType.DEPLOY,
402                                         artifactInfo.getArtifactURL (),
403                           asdcConfig.getConsumerID (),
404                           vfResourceStructure.getNotification().getDistributionID(),
405                           DistributionStatusEnum.DEPLOY_ERROR,
406                           "The artifact has not been used by the modules defined in the resource",
407                           System.currentTimeMillis ());
408                 } else {
409                         this.sendASDCNotification (NotificationType.DEPLOY,
410                                         artifactInfo.getArtifactURL (),
411                           asdcConfig.getConsumerID (),
412                           vfResourceStructure.getNotification().getDistributionID(),
413                           distribStatus,
414                           errorReason,
415                           System.currentTimeMillis ());
416                 }
417         }
418     }
419     
420     protected void sendCsarDeployNotification(INotificationData iNotif, VfResourceStructure resourceStructure, ToscaResourceStructure toscaResourceStructure, boolean deploySuccessful, String errorReason) {
421         
422                 IArtifactInfo csarArtifact = toscaResourceStructure.getToscaArtifact();
423                 
424                 if(deploySuccessful){
425                         
426                 this.sendASDCNotification (NotificationType.DEPLOY,
427                                   csarArtifact.getArtifactURL (),
428                           asdcConfig.getConsumerID (),
429                           resourceStructure.getNotification().getDistributionID(),
430                           DistributionStatusEnum.DEPLOY_OK,
431                           errorReason,
432                           System.currentTimeMillis ());
433                         
434                 } else {
435                         
436                         this.sendASDCNotification (NotificationType.DEPLOY,
437                           csarArtifact.getArtifactURL (),
438                   asdcConfig.getConsumerID (),
439                   resourceStructure.getNotification().getDistributionID(),
440                   DistributionStatusEnum.DEPLOY_ERROR,
441                   errorReason,
442                   System.currentTimeMillis ());
443                         
444                 }
445     }
446     
447     protected void deployResourceStructure (VfResourceStructure resourceStructure, ToscaResourceStructure toscaResourceStructure) throws ArtifactInstallerException {
448
449         LOGGER.info (MessageEnum.ASDC_START_DEPLOY_ARTIFACT, resourceStructure.getResourceInstance().getResourceInstanceName(), resourceStructure.getResourceInstance().getResourceUUID(), "ASDC");
450         try {
451                 String resourceType = resourceStructure.getResourceInstance().getResourceType();
452                 String category = resourceStructure.getResourceInstance().getCategory();
453                 if("VF".equals(resourceType) && !"Allotted Resource".equalsIgnoreCase(category)){
454                         resourceStructure.createVfModuleStructures();
455                 }
456                 toscaInstaller.installTheResource(toscaResourceStructure, resourceStructure);                                                   
457
458         } catch (ArtifactInstallerException e) {
459                 LOGGER.info (MessageEnum.ASDC_ARTIFACT_DOWNLOAD_FAIL,
460                                 resourceStructure.getResourceInstance().getResourceName(),
461                                 resourceStructure.getResourceInstance().getResourceUUID(),
462                         String.valueOf (resourceStructure.getVfModuleStructure().size()), "ASDC", "deployResourceStructure");
463                 sendDeployNotificationsForResource(resourceStructure,DistributionStatusEnum.DEPLOY_ERROR,e.getMessage());
464                 throw e;
465         }
466
467         if (resourceStructure.isDeployedSuccessfully() || toscaResourceStructure.isDeployedSuccessfully()) {
468                 LOGGER.info (MessageEnum.ASDC_ARTIFACT_DEPLOY_SUC,
469                                 resourceStructure.getResourceInstance().getResourceName(),
470                                 resourceStructure.getResourceInstance().getResourceUUID(),
471                         String.valueOf (resourceStructure.getVfModuleStructure().size()), "ASDC", "deployResourceStructure");
472                 sendDeployNotificationsForResource(resourceStructure,DistributionStatusEnum.DEPLOY_OK ,null);
473         }
474
475     }
476     
477
478     private enum NotificationType {
479         DOWNLOAD, DEPLOY
480     }
481
482     protected void sendASDCNotification (NotificationType notificationType,
483                                        String artifactURL,
484                                        String consumerID,
485                                        String distributionID,
486                                        DistributionStatusEnum status,
487                                        String errorReason,
488                                        long timestamp) {
489
490         String event = "Sending " + notificationType.name ()
491                        + "("
492                        + status.name ()
493                        + ")"
494                        + " notification to ASDC for artifact:"
495                        + artifactURL;
496
497         if (errorReason != null) {
498                 event=event+"("+errorReason+")";
499         }
500         LOGGER.info (MessageEnum.ASDC_SEND_NOTIF_ASDC, notificationType.name (), status.name (), artifactURL, "ASDC", "sendASDCNotification");
501         LOGGER.debug (event);
502
503         long subStarttime = System.currentTimeMillis ();
504         String action = "";
505         try {
506             IDistributionStatusMessage message = new DistributionStatusMessage (artifactURL,
507                                                                                 consumerID,
508                                                                                 distributionID,
509                                                                                 status,
510                                                                                 timestamp);
511
512             switch (notificationType) {
513                 case DOWNLOAD:
514                     if (errorReason != null) {
515                         this.distributionClient.sendDownloadStatus (message, errorReason);
516                     } else {
517                         this.distributionClient.sendDownloadStatus (message);
518                     }
519                     action = "sendDownloadStatus";
520                     break;
521                 case DEPLOY:
522                     if (errorReason != null) {
523                         this.distributionClient.sendDeploymentStatus (message, errorReason);
524                     } else {
525                         this.distributionClient.sendDeploymentStatus (message);
526                     }
527                     action = "sendDeploymentdStatus";
528                     break;
529                 default:
530                         break;
531             }
532         } catch (RuntimeException e) {           
533             LOGGER.warn (MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC, "ASDC", "sendASDCNotification", MsoLogger.ErrorCode.SchemaError, "RuntimeException - sendASDCNotification", e);
534         }
535         LOGGER.recordMetricEvent (subStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully sent notification to ASDC", "ASDC", action, null);
536     }
537     
538     protected void sendFinalDistributionStatus (
539                 String distributionID,
540                 DistributionStatusEnum status,
541                 String errorReason) {
542
543
544         LOGGER.debug ("Enter sendFinalDistributionStatus with DistributionID " + distributionID + " and Status of " + status.name() + " and ErrorReason " + errorReason);
545
546         long subStarttime = System.currentTimeMillis ();
547         try {
548                 
549                 
550                 IFinalDistrStatusMessage finalDistribution = new FinalDistributionStatusMessage(distributionID,status,subStarttime, asdcConfig.getConsumerID());
551                 
552                 if(errorReason == null){
553                         this.distributionClient.sendFinalDistrStatus(finalDistribution);
554                 }else{
555                         this.distributionClient.sendFinalDistrStatus(finalDistribution, errorReason);
556                 }
557                 
558  
559         } catch (RuntimeException e) {                  
560                 LOGGER.debug ("Exception caught in sendFinalDistributionStatus " + e.getMessage());
561                 LOGGER.warn (MessageEnum.ASDC_SEND_NOTIF_ASDC_EXEC, "ASDC", "sendASDCNotification", MsoLogger.ErrorCode.SchemaError, "RuntimeException - sendASDCNotification", e);
562         }
563         LOGGER.recordMetricEvent (subStarttime, MsoLogger.StatusCode.COMPLETE, MsoLogger.ResponseCode.Suc, "Successfully sent Final notification to ASDC", "ASDC", null, null);
564     }
565
566         private Optional<String> getNotificationJson(INotificationData iNotif) {
567                 ObjectMapper mapper = new ObjectMapper();
568                 mapper.setSerializationInclusion(Include.NON_NULL);
569                 mapper.setSerializationInclusion(Include.NON_EMPTY);
570                 mapper.setSerializationInclusion(Include.NON_ABSENT);
571         mapper.enable(MapperFeature.USE_ANNOTATIONS);
572         mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
573                 Optional<String> returnValue = Optional.empty();
574                 try {
575                         returnValue = Optional.of(mapper.writeValueAsString(iNotif));
576                 } catch (JsonProcessingException e) {
577                         LOGGER.error("Error converting incoming ASDC notification to JSON" , e);
578                 }
579                 return returnValue;
580         }
581         
582     public void treatNotification (INotificationData iNotif) {
583
584         int noOfArtifacts = 0;
585         
586
587         for (IResourceInstance resource : iNotif.getResources ()) {
588                 noOfArtifacts += resource.getArtifacts ().size ();
589         }
590         LOGGER.info (MessageEnum.ASDC_RECEIVE_CALLBACK_NOTIF,
591                      String.valueOf (noOfArtifacts),
592                      iNotif.getServiceUUID (), "ASDC");
593
594         try {
595                 LOGGER.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
596                         LOGGER.info(MessageEnum.ASDC_RECEIVE_SERVICE_NOTIF, iNotif.getServiceUUID(), "ASDC", "treatNotification");
597                                                 
598                         this.changeControllerStatus(ASDCControllerStatus.BUSY);
599                         Optional<String> notificationMessage = getNotificationJson(iNotif);
600                         toscaInstaller.processWatchdog(iNotif.getDistributionID(), iNotif.getServiceUUID(), notificationMessage,
601                                         asdcConfig.getConsumerID());
602                         
603                         // Process only the Resource artifacts in MSO                           
604                         this.processResourceNotification(iNotif);
605                         
606                         //********************************************************************************************************
607                         //Start Watchdog loop and wait for all components to complete before reporting final status back. 
608                         // **If timer expires first then we will report a Distribution Error back to ASDC
609                         //********************************************************************************************************
610                 long initialStartTime = System.currentTimeMillis();
611                 boolean componentsComplete = false;
612                 String distributionStatus = null;
613                 String watchdogError = null;
614                 String overallStatus = null;
615                 int watchDogTimeout = asdcConfig.getWatchDogTimeout() * 1000;
616                 boolean isDeploySuccess = false;                
617                                                 
618                 while(!componentsComplete && (System.currentTimeMillis() - initialStartTime) < watchDogTimeout)
619                 {
620                                                 
621                         try{                    
622                                 distributionStatus = wd.getOverallDistributionStatus(iNotif.getDistributionID());
623                                 Thread.sleep(watchDogTimeout / 10);             
624                         }catch(Exception e){
625                                 LOGGER.debug ("Exception in Watchdog Loop " + e.getMessage());
626                                 Thread.sleep(watchDogTimeout / 10);
627                         }
628                         
629                         if(distributionStatus != null && !distributionStatus.equalsIgnoreCase(DistributionStatus.INCOMPLETE.name())){
630                                 
631                                 if(distributionStatus.equalsIgnoreCase(DistributionStatus.SUCCESS.name())){
632                                         isDeploySuccess = true;
633                                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.name();
634                                 }else{
635                                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
636                                 }                               
637                                 componentsComplete = true;
638                         }
639                 }
640                 
641                 if(!componentsComplete){
642                         LOGGER.debug("Timeout of " + watchDogTimeout + " seconds was reached before all components reported status");
643                         watchdogError = "Timeout occurred while waiting for all components to report status";
644                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
645                 }
646                 
647                 if(distributionStatus == null){         
648                         overallStatus = DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name();
649                         LOGGER.debug("DistributionStatus is null for DistributionId: " + iNotif.getDistributionID());                           
650                 }
651                 
652                 try {
653                         wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(), overallStatus);
654                         LOGGER.debug ("A&AI Updated succefully with Distribution Status!");
655                 }
656                 catch(Exception e) {
657                         LOGGER.debug ("Exception in Watchdog executePatchAAI(): " + e.getMessage());
658                         watchdogError = "Error calling A&AI " + e.getMessage();
659                         if(e.getCause() != null) {
660                                 LOGGER.debug ("Exception caused by: " + e.getCause().getMessage());
661                         }
662                 }
663         
664                 
665                 if(isDeploySuccess && watchdogError == null){
666                         sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK, null);
667                         WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
668                         wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_OK.toString());
669                         wdsRepo.save(wds);
670                 } else {
671                         sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR, watchdogError);
672                         WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
673                         wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
674                         wdsRepo.save(wds);
675                 }
676                 
677
678         } catch(ObjectOptimisticLockingFailureException e) {
679                 
680                 LOGGER.debug ("OptimisticLockingFailure for DistributionId: " + iNotif.getDistributionID() + " Another process has already altered this distribution, so not going to process it on this site.");
681                 LOGGER.error (MessageEnum.ASDC_GENERAL_EXCEPTION_ARG,
682                     "Database concurrency exception: ",  "ASDC", "treatNotification", MsoLogger.ErrorCode.BusinessProcesssError, "RuntimeException in treatNotification",
683                     e);
684                 
685         } catch (Exception e) {
686             LOGGER.error (MessageEnum.ASDC_GENERAL_EXCEPTION_ARG,
687                           "Unexpected exception caught during the notification processing",  "ASDC", "treatNotification", MsoLogger.ErrorCode.SchemaError, "RuntimeException in treatNotification",
688                           e);
689             
690                 try {
691                         wd.executePatchAAI(iNotif.getDistributionID(), iNotif.getServiceInvariantUUID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
692                         LOGGER.debug ("A&AI Updated succefully with Distribution Status of " + DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.name());
693                 }
694                 catch(Exception aaiException) {
695                         LOGGER.debug ("Exception in executePatchAAI(): " + aaiException);
696                         if(aaiException.getCause() != null) {
697                                 LOGGER.debug ("Exception caused by: " + aaiException.getCause().getMessage());
698                         }
699                 }
700             
701              sendFinalDistributionStatus(iNotif.getDistributionID(), DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR, e.getMessage());
702              
703                  WatchdogDistributionStatus wds = new WatchdogDistributionStatus(iNotif.getDistributionID());
704                  wds.setDistributionIdStatus(DistributionStatusEnum.DISTRIBUTION_COMPLETE_ERROR.toString());
705                  wdsRepo.save(wds);
706             
707         } finally {
708             this.changeControllerStatus (ASDCControllerStatus.IDLE);
709         }
710     }
711
712     protected void processResourceNotification (INotificationData iNotif) {
713         // For each artifact, create a structure describing the VFModule in a ordered flat level
714         VfResourceStructure resourceStructure = null;
715         ToscaResourceStructure toscaResourceStructure = new ToscaResourceStructure();
716         boolean deploySuccessful = true;
717         boolean hasVFResource = false;
718         String errorMessage = null;
719
720         try {
721                 
722                         this.processCsarServiceArtifacts(iNotif, toscaResourceStructure);
723                         IArtifactInfo iArtifact = toscaResourceStructure.getToscaArtifact();
724                         String filePath = System.getProperty("mso.config.path") + "/ASDC/" + iArtifact.getArtifactVersion() + "/" + iArtifact.getArtifactName();
725                         File csarFile = new File(filePath);
726                         String csarFilePath = csarFile.getAbsolutePath();
727                         if (bpmnInstaller.containsWorkflows(csarFilePath)) {
728                                 bpmnInstaller.installBpmn(csarFilePath);
729                         }                       
730                                                 
731                 for (IResourceInstance resource : iNotif.getResources()){
732                         
733                         resourceStructure = new VfResourceStructure(iNotif,resource);
734                         
735                         String resourceType = resourceStructure.getResourceInstance().getResourceType();
736                 String category = resourceStructure.getResourceInstance().getCategory();
737                                         
738                 LOGGER.debug("Processing Resource Type: " + resourceType + " and Model UUID: " + resourceStructure.getResourceInstance().getResourceUUID());
739                         
740                                 if("VF".equals(resourceType) && !"Allotted Resource".equalsIgnoreCase(category)){
741                                         
742                                         hasVFResource = true;
743                         
744                                 for (IArtifactInfo artifact : resource.getArtifacts()) {
745                                         IDistributionClientDownloadResult resultArtifact = this.downloadTheArtifact(artifact,
746                                                         iNotif.getDistributionID());
747                                         if (resultArtifact != null) {
748                                                                                         
749                                                 if (ASDCConfiguration.VF_MODULES_METADATA.equals(artifact.getArtifactType())) {
750                                                         LOGGER.debug("VF_MODULE_ARTIFACT: "+new String(resultArtifact.getArtifactPayload(),"UTF-8"));
751                                                         LOGGER.debug(ASDCNotificationLogging.dumpVfModuleMetaDataList(resourceStructure.decodeVfModuleArtifact(resultArtifact.getArtifactPayload())));
752                                                 }
753                                                 resourceStructure.addArtifactToStructure(distributionClient,artifact, resultArtifact);
754                                         }
755                                 }
756                                 
757                                         //Deploy VF resource and artifacts
758                                         LOGGER.debug("Preparing to deploy Service: " + iNotif.getServiceUUID());
759                                         try{
760                                                 
761                                                 this.deployResourceStructure(resourceStructure, toscaResourceStructure);
762
763                                         } catch(ArtifactInstallerException e){
764                                                 deploySuccessful = false;
765                                                 errorMessage = e.getMessage();
766                                                 LOGGER.error(e);
767                                         }  
768                                 }
769                                                 
770                 }       
771                 
772                         // There are cases where the Service has no VF resources, those are handled here
773                         if (!hasVFResource) {
774                                 
775                                 LOGGER.debug("No resources found for Service: " + iNotif.getServiceUUID());
776                                 
777                                 try{
778                                         resourceStructure = new VfResourceStructure(iNotif,new ResourceInstance()); 
779                                         
780                                         this.deployResourceStructure(resourceStructure, toscaResourceStructure);
781
782                                 } catch(ArtifactInstallerException e){
783                                         deploySuccessful = false;
784                                         errorMessage = e.getMessage();
785                                         LOGGER.error(e);
786                    }
787                 }
788                          this.sendCsarDeployNotification(iNotif, resourceStructure, toscaResourceStructure, deploySuccessful, errorMessage);
789                 
790         } catch (ASDCDownloadException | UnsupportedEncodingException e) {
791                 LOGGER.error(MessageEnum.ASDC_GENERAL_EXCEPTION_ARG,
792                                 "Exception caught during Installation of artifact", "ASDC", "processResourceNotification", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in processResourceNotification", e);
793         }
794     }
795     protected void processCsarServiceArtifacts (INotificationData iNotif, ToscaResourceStructure toscaResourceStructure) {
796         
797         List<IArtifactInfo> serviceArtifacts = iNotif.getServiceArtifacts();
798         
799                 for(IArtifactInfo artifact : serviceArtifacts){
800                 
801                         if(artifact.getArtifactType().equals(ASDCConfiguration.TOSCA_CSAR)){
802                                 
803                                 try{
804                                         
805                                         toscaResourceStructure.setToscaArtifact(artifact);
806                                         
807                                         IDistributionClientDownloadResult resultArtifact = this.downloadTheArtifact(artifact,iNotif.getDistributionID());
808                                         
809                                         writeArtifactToFile(artifact, resultArtifact);
810                                         
811                                         toscaResourceStructure.updateResourceStructure(artifact);
812                                         
813                                         toscaResourceStructure.setServiceVersion(iNotif.getServiceVersion());
814                                         
815                                         LOGGER.debug(ASDCNotificationLogging.dumpCSARNotification(iNotif, toscaResourceStructure));
816                                         
817
818                                 } catch(Exception e){
819                                         LOGGER.error(MessageEnum.ASDC_GENERAL_EXCEPTION_ARG,
820                                                         "Exception caught during processCsarServiceArtifacts", "ASDC", "processCsarServiceArtifacts", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in processCsarServiceArtifacts", e);
821                                 }
822                         }
823                         else if(artifact.getArtifactType().equals(ASDCConfiguration.WORKFLOWS)){
824                                 
825                                 try{                                    
826                                         
827                                         IDistributionClientDownloadResult resultArtifact = this.downloadTheArtifact(artifact,iNotif.getDistributionID());
828                                         
829                                         writeArtifactToFile(artifact, resultArtifact);
830                                         
831                                         toscaResourceStructure.setToscaArtifact(artifact);
832                                         
833                                         LOGGER.debug(ASDCNotificationLogging.dumpASDCNotification(iNotif));
834                                         
835
836                                 } catch(Exception e){
837                                         System.out.println("Whats the error " + e.getMessage());
838                                         LOGGER.error(MessageEnum.ASDC_GENERAL_EXCEPTION_ARG,
839                                                         "Exception caught during processCsarServiceArtifacts", "ASDC", "processCsarServiceArtifacts", MsoLogger.ErrorCode.BusinessProcesssError, "Exception in processCsarServiceArtifacts", e);
840                                 }
841                         }
842
843                                 
844                 }
845     }
846     
847     private static final String UNKNOWN="Unknown";
848     
849     /**
850      * @return the address of the ASDC we are connected to.
851      */
852     public String getAddress () {
853         if (asdcConfig != null) {
854             return asdcConfig.getAsdcAddress ();
855         }
856         return UNKNOWN;
857     }
858
859     /**
860      * @return the environment name of the ASDC we are connected to.
861      */
862     public String getEnvironment () {
863         if (asdcConfig != null) {
864             return asdcConfig.getEnvironmentName ();
865         }
866         return UNKNOWN;
867     }
868
869 }