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