Modify to work with new drools-pdp
[policy/drools-applications.git] / controlloop / common / eventmanager / src / main / java / org / onap / policy / controlloop / eventmanager / ControlLoopOperationManager.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop operation manager
4  * ================================================================================
5  * Copyright (C) 2017-2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2019 Huawei Technologies Co., Ltd. All rights reserved.
7  * Modifications Copyright (C) 2019 Tech Mahindra
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.controlloop.eventmanager;
24
25 import java.io.Serializable;
26 import java.sql.Timestamp;
27 import java.time.Instant;
28 import java.util.AbstractMap;
29 import java.util.LinkedList;
30 import java.util.List;
31 import java.util.NoSuchElementException;
32 import java.util.Properties;
33 import javax.persistence.EntityManager;
34 import javax.persistence.Persistence;
35 import org.eclipse.persistence.config.PersistenceUnitProperties;
36 import org.onap.aai.domain.yang.GenericVnf;
37 import org.onap.policy.aai.util.AaiException;
38 import org.onap.policy.appc.Response;
39 import org.onap.policy.appc.ResponseCode;
40 import org.onap.policy.appclcm.LcmResponseWrapper;
41 import org.onap.policy.controlloop.ControlLoopEvent;
42 import org.onap.policy.controlloop.ControlLoopException;
43 import org.onap.policy.controlloop.ControlLoopOperation;
44 import org.onap.policy.controlloop.ControlLoopResponse;
45 import org.onap.policy.controlloop.VirtualControlLoopEvent;
46 import org.onap.policy.controlloop.actor.appc.AppcActorServiceProvider;
47 import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider;
48 import org.onap.policy.controlloop.actor.sdnc.SdncActorServiceProvider;
49 import org.onap.policy.controlloop.actor.sdnr.SdnrActorServiceProvider;
50 import org.onap.policy.controlloop.actor.so.SoActorServiceProvider;
51 import org.onap.policy.controlloop.actor.vfc.VfcActorServiceProvider;
52 import org.onap.policy.controlloop.policy.Policy;
53 import org.onap.policy.controlloop.policy.PolicyResult;
54 import org.onap.policy.database.operationshistory.Dbao;
55 import org.onap.policy.drools.system.PolicyEngineConstants;
56 import org.onap.policy.guard.Util;
57 import org.onap.policy.sdnc.SdncResponse;
58 import org.onap.policy.sdnr.PciResponseWrapper;
59 import org.onap.policy.so.SoResponseWrapper;
60 import org.onap.policy.vfc.VfcResponse;
61 import org.slf4j.Logger;
62 import org.slf4j.LoggerFactory;
63
64 public class ControlLoopOperationManager implements Serializable {
65     private static final String SUCCESS_MSG = " Success";
66     private static final String FAILED_MSG = " Failed";
67     private static final String AAI_CUSTOM_QUERY = "aai.customQuery";
68     private static final long serialVersionUID = -3773199283624595410L;
69     private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
70
71     private static final String VSERVER_VSERVER_NAME = "vserver.vserver-name";
72     private static final String GENERIC_VNF_VNF_NAME = "generic-vnf.vnf-name";
73     private static final String GENERIC_VNF_VNF_ID = "generic-vnf.vnf-id";
74
75     //
76     // These properties are not changeable, but accessible
77     // for Drools Rule statements.
78     //
79     public final ControlLoopEvent onset;
80     public final Policy policy;
81
82     //
83     // Properties used to track the Operation
84     //
85     private int attempts = 0;
86     private Operation currentOperation = null;
87     private LinkedList<Operation> operationHistory = new LinkedList<>();
88     private PolicyResult policyResult = null;
89     private ControlLoopEventManager eventManager = null;
90     private String targetEntity;
91     private String guardApprovalStatus = "NONE";// "NONE", "PERMIT", "DENY"
92     private transient Object operationRequest;
93
94     /**
95      * Construct an instance.
96      *
97      * @param onset the onset event
98      * @param policy the policy
99      * @param em the event manager
100      * @throws ControlLoopException if an error occurs
101      */
102     public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em)
103             throws ControlLoopException {
104
105         this.onset = onset;
106         this.policy = policy;
107         this.guardApprovalStatus = "NONE";
108         this.eventManager = em;
109         this.targetEntity = getTarget(policy);
110
111         try {
112
113             //
114             // Let's make a sanity check
115             //
116             switch (policy.getActor()) {
117                 case "APPC":
118                     initAppc(onset, policy);
119                     break;
120                 case "SO":
121                     break;
122                 case "SDNR":
123                     break;
124                 case "VFC":
125                     break;
126                 case "SDNC":
127                     break;
128                 default:
129                     throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
130             }
131
132         } catch (AaiException e) {
133             throw new ControlLoopException(e.getMessage(), e);
134         }
135     }
136
137
138     private void initAppc(ControlLoopEvent onset, Policy policy) throws AaiException {
139         if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
140             /*
141              * The target vnf-id may not be the same as the source vnf-id specified in the yaml, the target
142              * vnf-id is retrieved by a named query to A&AI.
143              */
144             if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
145                 GenericVnf genvnf = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset)
146                         .getGenericVnfByModelInvariantId(policy.getTarget().getResourceID());
147                 if (genvnf == null) {
148                     logger.info("Target entity could not be found");
149                     throw new AaiException("Target vnf-id could not be found");
150                 }
151                 this.targetEntity = genvnf.getVnfId();
152
153             } else {
154                 this.targetEntity =
155                         AppcLcmActorServiceProvider.vnfNamedQuery(policy.getTarget().getResourceID(),
156                                 this.targetEntity, PolicyEngineConstants.getManager().getEnvironmentProperty("aai.url"),
157                                 PolicyEngineConstants.getManager().getEnvironmentProperty("aai.username"),
158                                 PolicyEngineConstants.getManager().getEnvironmentProperty("aai.password"));
159             }
160         }
161     }
162
163
164     public ControlLoopEventManager getEventManager() {
165         return eventManager;
166     }
167
168     public void setEventManager(ControlLoopEventManager eventManager) {
169         this.eventManager = eventManager;
170     }
171
172     public String getTargetEntity() {
173         return this.targetEntity;
174     }
175
176     @Override
177     public String toString() {
178         return "ControlLoopOperationManager [onset=" + (onset != null ? onset.getRequestId() : "null") + ", policy="
179                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts + ", policyResult="
180                 + policyResult + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
181                 + "]";
182     }
183
184     //
185     // Internal class used for tracking
186     //
187     private class Operation implements Serializable {
188         private static final long serialVersionUID = 1L;
189
190         private ControlLoopOperation clOperation = new ControlLoopOperation();
191         private PolicyResult policyResult = null;
192         private int attempt = 0;
193
194         @Override
195         public String toString() {
196             return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + clOperation
197                     + "]";
198         }
199     }
200
201     public Object getOperationRequest() {
202         return operationRequest;
203     }
204
205     public String getGuardApprovalStatus() {
206         return guardApprovalStatus;
207     }
208
209     public void setGuardApprovalStatus(String guardApprovalStatus) {
210         this.guardApprovalStatus = guardApprovalStatus;
211     }
212
213     /**
214      * Get the target for a policy.
215      *
216      * @param policy the policy
217      * @return the target
218      * @throws ControlLoopException if an error occurs
219      */
220     public String getTarget(Policy policy) throws ControlLoopException {
221         if (policy.getTarget() == null) {
222             throw new ControlLoopException("The target is null");
223         }
224
225         if (policy.getTarget().getType() == null) {
226             throw new ControlLoopException("The target type is null");
227         }
228
229         switch (policy.getTarget().getType()) {
230             case PNF:
231                 throw new ControlLoopException("PNF target is not supported");
232             case VM:
233             case VNF:
234                 return getVfModuleTarget();
235             case VFMODULE:
236                 return getVfModuleTarget();
237             default:
238                 throw new ControlLoopException("The target type is not supported");
239         }
240     }
241
242
243     private String getVfModuleTarget() throws ControlLoopException {
244         VirtualControlLoopEvent virtualOnsetEvent = (VirtualControlLoopEvent) this.onset;
245         if (this.onset.getTarget().equalsIgnoreCase(VSERVER_VSERVER_NAME)) {
246             return virtualOnsetEvent.getAai().get(VSERVER_VSERVER_NAME);
247         } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_ID)) {
248             return virtualOnsetEvent.getAai().get(GENERIC_VNF_VNF_ID);
249         } else if (this.onset.getTarget().equalsIgnoreCase(GENERIC_VNF_VNF_NAME)) {
250             /*
251              * If the onset is enriched with the vnf-id, we don't need an A&AI response
252              */
253             if (virtualOnsetEvent.getAai().containsKey(GENERIC_VNF_VNF_ID)) {
254                 return virtualOnsetEvent.getAai().get(GENERIC_VNF_VNF_ID);
255             }
256
257             /*
258              * If the vnf-name was retrieved from the onset then the vnf-id must be obtained from the event
259              * manager's A&AI GET query
260              */
261             try {
262                 String vnfId;
263                 if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
264                     vnfId = this.eventManager.getCqResponse((VirtualControlLoopEvent) onset).getDefaultGenericVnf()
265                             .getVnfId();
266                 } else {
267                     vnfId = this.eventManager.getVnfResponse().getVnfId();
268                 }
269                 if (vnfId == null) {
270                     throw new AaiException("No vnf-id found");
271                 }
272                 return vnfId;
273
274             } catch (AaiException e) {
275                 throw new ControlLoopException(e.getMessage(), e);
276             }
277         }
278         throw new ControlLoopException("Target does not match target type");
279     }
280
281     /**
282      * Start an operation.
283      *
284      * @param onset the onset event
285      * @return the operation request
286      * @throws ControlLoopException if an error occurs
287      */
288     public Object startOperation(/* VirtualControlLoopEvent */ControlLoopEvent onset)
289             throws ControlLoopException {
290         verifyOperatonCanRun();
291
292         //
293         // Setup
294         //
295         this.policyResult = null;
296         Operation operation = new Operation();
297         operation.attempt = ++this.attempts;
298         operation.clOperation.setActor(this.policy.getActor());
299         operation.clOperation.setOperation(this.policy.getRecipe());
300         operation.clOperation.setTarget(this.policy.getTarget().toString());
301         operation.clOperation.setSubRequestId(Integer.toString(operation.attempt));
302         //
303         // Now determine which actor we need to construct a request for
304         //
305         try {
306             switch (policy.getActor()) {
307                 case "APPC":
308                     return startAppcOperation(onset, operation);
309                 case "SO":
310                     return startSoOperation(onset, operation);
311                 case "VFC":
312                     return startVfcOperation(onset, operation);
313                 case "SDNR":
314                     return startSdnrOperation(onset, operation);
315                 case "SDNC":
316                     return startSdncOperation(onset, operation);
317                 default:
318                     throw new ControlLoopException("invalid actor " + policy.getActor() + " on policy");
319             }
320
321         } catch (AaiException e) {
322             throw new ControlLoopException(e.getMessage(), e);
323         }
324     }
325
326
327     private Object startAppcOperation(ControlLoopEvent onset, Operation operation) {
328         /*
329          * If the recipe is ModifyConfig, a legacy APPC request is constructed. Otherwise an LCMRequest is
330          * constructed.
331          */
332         this.currentOperation = operation;
333         if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
334             this.operationRequest = AppcActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
335                     operation.clOperation, this.policy, this.targetEntity);
336         } else {
337             this.operationRequest = AppcLcmActorServiceProvider.constructRequest(
338                     (VirtualControlLoopEvent) onset, operation.clOperation, this.policy, this.targetEntity);
339         }
340         //
341         // Save the operation
342         //
343
344         return operationRequest;
345     }
346
347
348     private Object startSoOperation(ControlLoopEvent onset, Operation operation) throws AaiException {
349         SoActorServiceProvider soActorSp = new SoActorServiceProvider();
350         if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
351             this.operationRequest =
352                     soActorSp.constructRequestCq((VirtualControlLoopEvent) onset, operation.clOperation,
353                             this.policy, eventManager.getCqResponse((VirtualControlLoopEvent) onset));
354         } else {
355             this.operationRequest = soActorSp.constructRequest((VirtualControlLoopEvent) onset,
356                     operation.clOperation, this.policy, eventManager.getNqVserverFromAai());
357         }
358
359         // Save the operation
360         this.currentOperation = operation;
361
362         if (this.operationRequest == null) {
363             this.policyResult = PolicyResult.FAILURE;
364         }
365
366         return operationRequest;
367     }
368
369
370     private Object startVfcOperation(ControlLoopEvent onset, Operation operation) throws AaiException {
371         if (Boolean.valueOf(PolicyEngineConstants.getManager().getEnvironmentProperty(AAI_CUSTOM_QUERY))) {
372             this.operationRequest = VfcActorServiceProvider.constructRequestCq((VirtualControlLoopEvent) onset,
373                     operation.clOperation, this.policy,
374                     eventManager.getCqResponse((VirtualControlLoopEvent) onset));
375         } else {
376             this.operationRequest = VfcActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
377                     operation.clOperation, this.policy, this.eventManager.getVnfResponse(),
378                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.url"),
379                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.username"),
380                     PolicyEngineConstants.getManager().getEnvironmentProperty("vfc.password"));
381         }
382         this.currentOperation = operation;
383         if (this.operationRequest == null) {
384             this.policyResult = PolicyResult.FAILURE;
385         }
386         return operationRequest;
387     }
388
389
390     private Object startSdnrOperation(ControlLoopEvent onset, Operation operation) {
391         /*
392          * If the recipe is ModifyConfig or ModifyConfigANR, a SDNR request is constructed.
393          */
394         this.currentOperation = operation;
395         this.operationRequest = SdnrActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset,
396                 operation.clOperation, this.policy);
397         //
398         // Save the operation
399         //
400         if (this.operationRequest == null) {
401             this.policyResult = PolicyResult.FAILURE;
402         }
403
404         return operationRequest;
405     }
406
407
408     private Object startSdncOperation(ControlLoopEvent onset, Operation operation) {
409         SdncActorServiceProvider provider = new SdncActorServiceProvider();
410         this.operationRequest =
411                 provider.constructRequest((VirtualControlLoopEvent) onset, operation.clOperation, this.policy);
412         this.currentOperation = operation;
413         if (this.operationRequest == null) {
414             this.policyResult = PolicyResult.FAILURE;
415         }
416         return operationRequest;
417     }
418
419     /**
420      * Handle a response.
421      *
422      * @param response the response
423      * @return a PolicyResult
424      */
425     public PolicyResult onResponse(Object response) {
426         //
427         // Which response is it?
428         //
429         if (response instanceof Response) {
430             //
431             // Cast APPC response and handle it
432             //
433             return onResponse((Response) response);
434         } else if (response instanceof LcmResponseWrapper) {
435             //
436             // Cast LCM response and handle it
437             //
438             return onResponse((LcmResponseWrapper) response);
439         } else if (response instanceof PciResponseWrapper) {
440             //
441             // Cast SDNR response and handle it
442             //
443             return onResponse((PciResponseWrapper) response);
444         } else if (response instanceof SoResponseWrapper) {
445             //
446             // Cast SO response and handle it
447             //
448             return onResponse((SoResponseWrapper) response);
449         } else if (response instanceof VfcResponse) {
450             //
451             // Cast VFC response and handle it
452             //
453             return onResponse((VfcResponse) response);
454         } else if (response instanceof SdncResponse) {
455             //
456             // Cast SDNC response and handle it
457             //
458             return onResponse((SdncResponse) response);
459         } else {
460             return null;
461         }
462     }
463
464     /**
465      * This method handles operation responses from APPC.
466      *
467      * @param appcResponse the APPC response
468      * @return The result of the response handling
469      */
470     private PolicyResult onResponse(Response appcResponse) {
471         //
472         // Determine which subrequestID (ie. attempt)
473         //
474         Integer operationAttempt = getSubRequestId(appcResponse);
475         if (operationAttempt == null) {
476             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
477                             PolicyResult.FAILURE_EXCEPTION);
478             return PolicyResult.FAILURE_EXCEPTION;
479         }
480         //
481         // Sanity check the response message
482         //
483         if (appcResponse.getStatus() == null) {
484             //
485             // We cannot tell what happened if this doesn't exist
486             //
487             this.completeOperation(operationAttempt,
488                     "Policy was unable to parse APP-C response status field (it was null).",
489                     PolicyResult.FAILURE_EXCEPTION);
490             return PolicyResult.FAILURE_EXCEPTION;
491         }
492         //
493         // Get the Response Code
494         //
495         ResponseCode code = ResponseCode.toResponseCode(appcResponse.getStatus().getCode());
496         if (code == null) {
497             //
498             // We are unaware of this code
499             //
500             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.",
501                     PolicyResult.FAILURE_EXCEPTION);
502             return PolicyResult.FAILURE_EXCEPTION;
503         }
504
505         return onResponse(appcResponse, operationAttempt, code);
506     }
507
508
509     private PolicyResult onResponse(Response appcResponse, Integer operationAttempt, ResponseCode code) {
510         //
511         // Ok, let's figure out what APP-C's response is
512         //
513         switch (code) {
514             case ACCEPT:
515                 //
516                 // This is good, they got our original message and
517                 // acknowledged it.
518                 //
519                 // Is there any need to track this?
520                 //
521                 return null;
522             case ERROR:
523             case REJECT:
524                 //
525                 // We'll consider these two codes as exceptions
526                 //
527                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
528                         PolicyResult.FAILURE_EXCEPTION);
529                 return getTimeoutResult(PolicyResult.FAILURE_EXCEPTION);
530             case SUCCESS:
531                 //
532                 //
533                 //
534                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
535                         PolicyResult.SUCCESS);
536                 return getTimeoutResult(PolicyResult.SUCCESS);
537             case FAILURE:
538                 //
539                 //
540                 //
541                 this.completeOperation(operationAttempt, appcResponse.getStatus().getDescription(),
542                         PolicyResult.FAILURE);
543                 return getTimeoutResult(PolicyResult.FAILURE);
544             default:
545                 return null;
546         }
547     }
548
549     /**
550      * This method handles operation responses from LCM.
551      *
552      * @param dmaapResponse the LCM response
553      * @return The result of the response handling
554      */
555     private PolicyResult onResponse(LcmResponseWrapper dmaapResponse) {
556         /*
557          * Parse out the operation attempt using the subrequestid
558          */
559         Integer operationAttempt = AppcLcmActorServiceProvider
560                 .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
561         if (operationAttempt == null) {
562             this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).",
563                     PolicyResult.FAILURE_EXCEPTION);
564             return PolicyResult.FAILURE_EXCEPTION;
565         }
566
567         /*
568          * Process the APPCLCM response to see what PolicyResult should be returned
569          */
570         AbstractMap.SimpleEntry<PolicyResult, String> result =
571                 AppcLcmActorServiceProvider.processResponse(dmaapResponse);
572
573         if (result.getKey() != null) {
574             this.completeOperation(operationAttempt, result.getValue(), result.getKey());
575             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
576                 return null;
577             }
578             return result.getKey();
579         }
580         return null;
581     }
582
583     /**
584      * This method handles operation responses from SDNR.
585      *
586      * @param dmaapResponse the SDNR response
587      * @return the result of the response handling
588      */
589     private PolicyResult onResponse(PciResponseWrapper dmaapResponse) {
590         /*
591          * Parse out the operation attempt using the subrequestid
592          */
593         Integer operationAttempt = SdnrActorServiceProvider
594                 .parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
595         if (operationAttempt == null) {
596             this.completeOperation(operationAttempt, "Policy was unable to parse SDNR SubRequestID.",
597                     PolicyResult.FAILURE_EXCEPTION);
598             return PolicyResult.FAILURE_EXCEPTION;
599         }
600
601         /*
602          * Process the SDNR response to see what PolicyResult should be returned
603          */
604         SdnrActorServiceProvider.Pair<PolicyResult, String> result =
605                 SdnrActorServiceProvider.processResponse(dmaapResponse);
606
607         if (result.getResult() != null) {
608             this.completeOperation(operationAttempt, result.getMessage(), result.getResult());
609             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
610                 return null;
611             }
612             return result.getResult();
613         }
614         return null;
615     }
616
617     /**
618      * This method handles operation responses from SO.
619      *
620      * @param msoResponse the SO response
621      * @return The result of the response handling
622      */
623     private PolicyResult onResponse(SoResponseWrapper msoResponse) {
624         switch (msoResponse.getSoResponse().getHttpResponseCode()) {
625             case 200:
626             case 202:
627                 //
628                 // Consider it as success
629                 //
630                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + SUCCESS_MSG,
631                         PolicyResult.SUCCESS);
632                 return getTimeoutResult(PolicyResult.SUCCESS);
633             default:
634                 //
635                 // Consider it as failure
636                 //
637                 this.completeOperation(this.attempts, msoResponse.getSoResponse().getHttpResponseCode() + FAILED_MSG,
638                         PolicyResult.FAILURE);
639                 return getTimeoutResult(PolicyResult.FAILURE);
640         }
641     }
642
643     /**
644      * This method handles operation responses from VFC.
645      *
646      * @param vfcResponse the VFC response
647      * @return The result of the response handling
648      */
649     private PolicyResult onResponse(VfcResponse vfcResponse) {
650         if ("finished".equalsIgnoreCase(vfcResponse.getResponseDescriptor().getStatus())) {
651             //
652             // Consider it as success
653             //
654             this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS);
655             return getTimeoutResult(PolicyResult.SUCCESS);
656         } else {
657             //
658             // Consider it as failure
659             //
660             this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE);
661             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
662                 return null;
663             }
664             // increment operation attempts for retries
665             this.attempts += 1;
666             return PolicyResult.FAILURE;
667         }
668     }
669
670     /**
671      * This method handles operation responses from SDNC.
672      *
673      * @param sdncResponse the VFC response
674      * @return The result of the response handling
675      */
676     private PolicyResult onResponse(SdncResponse sdncResponse) {
677         if ("200".equals(sdncResponse.getResponseOutput().getResponseCode())) {
678             //
679             // Consider it as success
680             //
681             this.completeOperation(this.attempts, SUCCESS_MSG, PolicyResult.SUCCESS);
682             return getTimeoutResult(PolicyResult.SUCCESS);
683         } else {
684             //
685             // Consider it as failure
686             //
687             this.completeOperation(this.attempts, FAILED_MSG, PolicyResult.FAILURE);
688             if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
689                 return null;
690             }
691             // increment operation attempts for retries
692             this.attempts += 1;
693             return PolicyResult.FAILURE;
694         }
695     }
696
697     private PolicyResult getTimeoutResult(PolicyResult result) {
698         return (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult) ? null : result);
699     }
700
701
702     private Integer getSubRequestId(Response appcResponse) {
703         try {
704             return Integer.valueOf(appcResponse.getCommonHeader().getSubRequestId());
705         } catch (NumberFormatException e) {
706             //
707             // We cannot tell what happened if this doesn't exist
708             //
709             return null;
710         }
711     }
712
713     /**
714      * Get the operation timeout.
715      *
716      * @return the timeout
717      */
718     public Integer getOperationTimeout() {
719         //
720         // Sanity check
721         //
722         if (this.policy == null) {
723             logger.debug("getOperationTimeout returning 0");
724             return 0;
725         }
726         logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
727         return this.policy.getTimeout();
728     }
729
730     /**
731      * Get the operation timeout as a String.
732      *
733      * @param defaultTimeout the default timeout
734      * @return the timeout as a String
735      */
736     public String getOperationTimeoutString(int defaultTimeout) {
737         Integer to = this.getOperationTimeout();
738         if (to == null || to == 0) {
739             return Integer.toString(defaultTimeout) + "s";
740         }
741         return to.toString() + "s";
742     }
743
744     public PolicyResult getOperationResult() {
745         return this.policyResult;
746     }
747
748     /**
749      * Get the operation as a message.
750      *
751      * @return the operation as a message
752      */
753     public String getOperationMessage() {
754         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
755             return this.currentOperation.clOperation.toMessage();
756         }
757
758         if (!this.operationHistory.isEmpty()) {
759             return this.operationHistory.getLast().clOperation.toMessage();
760         }
761         return null;
762     }
763
764     /**
765      * Get the operation as a message including the guard result.
766      *
767      * @param guardResult the guard result
768      * @return the operation as a message including the guard result
769      */
770     public String getOperationMessage(String guardResult) {
771         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
772             return this.currentOperation.clOperation.toMessage() + ", Guard result: " + guardResult;
773         }
774
775         if (!this.operationHistory.isEmpty()) {
776             return this.operationHistory.getLast().clOperation.toMessage() + ", Guard result: " + guardResult;
777         }
778         return null;
779     }
780
781     /**
782      * Get the operation history.
783      *
784      * @return the operation history
785      */
786     public String getOperationHistory() {
787         if (this.currentOperation != null && this.currentOperation.clOperation != null) {
788             return this.currentOperation.clOperation.toHistory();
789         }
790
791         if (!this.operationHistory.isEmpty()) {
792             return this.operationHistory.getLast().clOperation.toHistory();
793         }
794         return null;
795     }
796
797     /**
798      * Get the history.
799      *
800      * @return the list of control loop operations
801      */
802     public List<ControlLoopOperation> getHistory() {
803         LinkedList<ControlLoopOperation> history = new LinkedList<>();
804         for (Operation op : this.operationHistory) {
805             history.add(new ControlLoopOperation(op.clOperation));
806
807         }
808         return history;
809     }
810
811     /**
812      * Set the operation has timed out.
813      */
814     public void setOperationHasTimedOut() {
815         //
816         //
817         //
818         this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
819     }
820
821     /**
822      * Set the operation has been denied by guard.
823      */
824     public void setOperationHasGuardDeny() {
825         //
826         //
827         //
828         this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
829     }
830
831     public void setOperationHasException(String message) {
832         this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
833     }
834
835     /**
836      * Is the operation complete.
837      *
838      * @return <code>true</code> if the operation is complete, <code>false</code> otherwise
839      */
840     public boolean isOperationComplete() {
841         //
842         // Is there currently a result?
843         //
844         if (this.policyResult == null) {
845             //
846             // either we are in process or we
847             // haven't started
848             //
849             return false;
850         }
851         //
852         // We have some result, check if the operation failed
853         //
854         if (this.policyResult.equals(PolicyResult.FAILURE)) {
855             //
856             // Check if there were no retries specified
857             //
858             if (policy.getRetry() == null || policy.getRetry() == 0) {
859                 //
860                 // The result is the failure
861                 //
862                 return true;
863             }
864             //
865             // Check retries
866             //
867             if (this.isRetriesMaxedOut()) {
868                 //
869                 // No more attempts allowed, reset
870                 // that our actual result is failure due to retries
871                 //
872                 this.policyResult = PolicyResult.FAILURE_RETRIES;
873                 return true;
874             } else {
875                 //
876                 // There are more attempts available to try the
877                 // policy recipe.
878                 //
879                 return false;
880             }
881         }
882         //
883         // Other results mean we are done
884         //
885         return true;
886     }
887
888     public boolean isOperationRunning() {
889         return (this.currentOperation != null);
890     }
891
892     /**
893      * This method verifies that the operation manager may run an operation.
894      *
895      * @return True if the operation can run, false otherwise
896      * @throws ControlLoopException if the operation cannot run
897      */
898     private void verifyOperatonCanRun() throws ControlLoopException {
899         //
900         // They shouldn't call us if we currently running something
901         //
902         if (this.currentOperation != null) {
903             //
904             // what do we do if we are already running an operation?
905             //
906             throw new ControlLoopException("current operation is not null (an operation is already running)");
907         }
908         //
909         // Check if we have maxed out on retries
910         //
911         if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
912             //
913             // No retries are allowed, so check have we even made
914             // one attempt to execute the operation?
915             //
916             if (this.attempts >= 1) {
917                 //
918                 // We have, let's ensure our PolicyResult is set
919                 //
920                 if (this.policyResult == null) {
921                     this.policyResult = PolicyResult.FAILURE_RETRIES;
922                 }
923                 //
924                 //
925                 //
926                 throw new ControlLoopException("current operation failed and retries are not allowed");
927             }
928         } else {
929             //
930             // Have we maxed out on retries?
931             //
932             if (this.attempts > this.policy.getRetry()) {
933                 if (this.policyResult == null) {
934                     this.policyResult = PolicyResult.FAILURE_RETRIES;
935                 }
936                 throw new ControlLoopException("current oepration has failed after " + this.attempts + " retries");
937             }
938         }
939     }
940
941     private boolean isRetriesMaxedOut() {
942         if (policy.getRetry() == null || policy.getRetry() == 0) {
943             //
944             // There were NO retries specified, so declare
945             // this as completed.
946             //
947             return (this.attempts > 0);
948         }
949         return (this.attempts > policy.getRetry());
950     }
951
952     private void storeOperationInDataBase() {
953         // Only store in DB if enabled
954         boolean guardEnabled = "false"
955                         .equalsIgnoreCase(PolicyEngineConstants.getManager().getEnvironmentProperty("guard.disabled"));
956         if (!guardEnabled) {
957             return;
958         }
959
960
961         // DB Properties
962         Properties props = new Properties();
963         if (PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_URL) != null
964                 && PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_USER) != null
965                         && PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_PASS) != null) {
966             props.put(Util.ECLIPSE_LINK_KEY_URL,
967                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_URL));
968             props.put(Util.ECLIPSE_LINK_KEY_USER,
969                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_USER));
970             props.put(Util.ECLIPSE_LINK_KEY_PASS,
971                             PolicyEngineConstants.getManager().getEnvironmentProperty(Util.ONAP_KEY_PASS));
972             props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
973         }
974
975
976         String opsHistPu = System.getProperty("OperationsHistoryPU");
977         if (!"OperationsHistoryPUTest".equals(opsHistPu)) {
978             opsHistPu = "OperationsHistoryPU";
979         } else {
980             props.clear();
981         }
982         EntityManager em;
983         try {
984             em = Persistence.createEntityManagerFactory(opsHistPu, props).createEntityManager();
985         } catch (Exception e) {
986             logger.error("storeOperationInDataBase threw: ", e);
987             return;
988         }
989
990         Dbao newEntry = new Dbao();
991
992         newEntry.setClosedLoopName(this.onset.getClosedLoopControlName());
993         newEntry.setRequestId(this.onset.getRequestId().toString());
994         newEntry.setActor(this.currentOperation.clOperation.getActor());
995         newEntry.setOperation(this.currentOperation.clOperation.getOperation());
996         newEntry.setTarget(this.targetEntity);
997         newEntry.setStarttime(Timestamp.from(this.currentOperation.clOperation.getStart()));
998         newEntry.setSubrequestId(this.currentOperation.clOperation.getSubRequestId());
999         newEntry.setEndtime(new Timestamp(this.currentOperation.clOperation.getEnd().toEpochMilli()));
1000         newEntry.setMessage(this.currentOperation.clOperation.getMessage());
1001         newEntry.setOutcome(this.currentOperation.clOperation.getOutcome());
1002
1003         em.getTransaction().begin();
1004         em.persist(newEntry);
1005         em.getTransaction().commit();
1006
1007         em.close();
1008     }
1009
1010     private void completeOperation(Integer attempt, String message, PolicyResult result) {
1011         if (attempt == null) {
1012             logger.debug("attempt cannot be null (i.e. subRequestID)");
1013             return;
1014         }
1015         if (this.currentOperation != null) {
1016             if (this.currentOperation.attempt == attempt.intValue()) {
1017                 this.currentOperation.clOperation.setEnd(Instant.now());
1018                 this.currentOperation.clOperation.setMessage(message);
1019                 this.currentOperation.clOperation.setOutcome(result.toString());
1020                 this.currentOperation.policyResult = result;
1021                 //
1022                 // Save it in history
1023                 //
1024                 this.operationHistory.add(this.currentOperation);
1025                 this.storeOperationInDataBase();
1026                 //
1027                 // Set our last result
1028                 //
1029                 this.policyResult = result;
1030                 //
1031                 // Clear the current operation field
1032                 //
1033                 this.currentOperation = null;
1034                 return;
1035             }
1036             logger.debug("not current");
1037         }
1038         for (Operation op : this.operationHistory) {
1039             if (op.attempt == attempt.intValue()) {
1040                 op.clOperation.setEnd(Instant.now());
1041                 op.clOperation.setMessage(message);
1042                 op.clOperation.setOutcome(result.toString());
1043                 op.policyResult = result;
1044                 return;
1045             }
1046         }
1047         logger.debug("Could not find associated operation");
1048     }
1049
1050
1051     /**
1052      * Commit the abatement to the history database.
1053      *
1054      * @param message the abatement message
1055      * @param outcome the abatement outcome
1056      */
1057     public void commitAbatement(String message, String outcome) {
1058         logger.info("commitAbatement: {}. {}", message, outcome);
1059
1060         if (this.currentOperation == null) {
1061             try {
1062                 this.currentOperation = this.operationHistory.getLast();
1063             } catch (NoSuchElementException e) {
1064                 logger.error("{}: commitAbatement threw an exception ", this, e);
1065                 return;
1066             }
1067         }
1068         this.currentOperation.clOperation.setEnd(Instant.now());
1069         this.currentOperation.clOperation.setMessage(message);
1070         this.currentOperation.clOperation.setOutcome(outcome);
1071         //
1072         // Store commit in DB
1073         //
1074         this.storeOperationInDataBase();
1075         //
1076         // Clear the current operation field
1077         //
1078         this.currentOperation = null;
1079     }
1080
1081     /**
1082      * Construct a ControlLoopResponse object from actor response and input event.
1083      *
1084      * @param response the response from actor
1085      * @param event the input event
1086      *
1087      * @return a ControlLoopResponse
1088      */
1089     public ControlLoopResponse getControlLoopResponse(Object response, VirtualControlLoopEvent event) {
1090         if (response instanceof PciResponseWrapper) {
1091             //
1092             // Cast SDNR response and handle it
1093             //
1094             return SdnrActorServiceProvider.getControlLoopResponse((PciResponseWrapper) response, event);
1095         } else {
1096             return null;
1097         }
1098     }
1099
1100 }