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