cebdc1e9a29573e107f7d50a04c4b1919f44fbeb
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * controlloop operation manager
4  * ================================================================================
5  * Copyright (C) 2017 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.Properties;
29
30 import javax.persistence.EntityManager;
31 import javax.persistence.Persistence;
32
33 import org.eclipse.persistence.config.PersistenceUnitProperties;
34 import org.onap.policy.aai.util.AAIException;
35 import org.onap.policy.appc.Response;
36 import org.onap.policy.appc.ResponseCode;
37 import org.onap.policy.appclcm.LCMResponseWrapper;
38 import org.onap.policy.controlloop.ControlLoopEvent;
39 import org.onap.policy.controlloop.ControlLoopException;
40 import org.onap.policy.controlloop.ControlLoopOperation;
41 import org.onap.policy.controlloop.VirtualControlLoopEvent;
42 import org.onap.policy.controlloop.actor.appc.APPCActorServiceProvider;
43 import org.onap.policy.controlloop.actor.appclcm.AppcLcmActorServiceProvider;
44 import org.onap.policy.controlloop.actor.so.SOActorServiceProvider;
45 import org.onap.policy.controlloop.actor.vfc.VFCActorServiceProvider;
46 import org.onap.policy.controlloop.policy.Policy;
47 import org.onap.policy.controlloop.policy.PolicyResult;
48 import org.onap.policy.drools.system.PolicyEngine;
49 import org.onap.policy.guard.Util;
50 import org.onap.policy.so.SOResponse;
51 import org.onap.policy.vfc.VFCResponse;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 public class ControlLoopOperationManager implements Serializable {
56
57         /**
58          *
59          */
60         private static final long serialVersionUID = -3773199283624595410L;
61         private static final Logger logger = LoggerFactory.getLogger(ControlLoopOperationManager.class);
62
63         @Override
64         public String toString() {
65                 return "ControlLoopOperationManager [onset=" + (onset != null ? onset.requestID : "null") + ", policy="
66                                 + (policy != null ? policy.getId() : "null") + ", attempts=" + attempts
67                                 + ", policyResult=" + policyResult
68                                 + ", currentOperation=" + currentOperation + ", operationHistory=" + operationHistory
69                                 + "]";
70         }
71
72         //
73         // These properties are not changeable, but accessible
74         // for Drools Rule statements.
75         //
76         //public final ATTControlLoopEvent onset;
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<Operation>();
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                 public ControlLoopOperation operation = new ControlLoopOperation();
107                 public PolicyResult policyResult = null;
108                 public int attempt = 0;
109
110                 @Override
111                 public String toString() {
112                         return "Operation [attempt=" + attempt + ", policyResult=" + policyResult + ", operation=" + operation
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         public void setGuardApprovalStatus(String guardApprovalStatus) {
128                 this.guardApprovalStatus = guardApprovalStatus;
129         }
130
131         public String getTarget(Policy policy) throws ControlLoopException, AAIException {
132         if (policy.getTarget() != null) {
133             if (policy.getTarget().getType() != null) {
134                 switch(policy.getTarget().getType()) {
135                 case PNF:
136                     break;
137                 case VM:
138                 case VNF:
139                     VirtualControlLoopEvent virtualOnset = (VirtualControlLoopEvent) this.onset;
140                     if (this.onset.target.equalsIgnoreCase("vserver.vserver-name")) {
141                         return virtualOnset.AAI.get("vserver.vserver-name");
142                     }
143                     else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-id")) {
144                         return virtualOnset.AAI.get("generic-vnf.vnf-id");
145                     }
146                     else if (this.onset.target.equalsIgnoreCase("generic-vnf.vnf-name")) {
147                         /*
148                          * If the vnf-name was retrieved from the onset then the vnf-id
149                          * must be obtained from the event manager's A&AI GET query
150                          */
151                         String vnfId = this.eventManager.getVnfResponse().vnfID;
152                         if (vnfId == null) {
153                             throw new AAIException("No vnf-id found");
154                         }
155                         return vnfId;
156                     }
157                     break;
158                 default:
159                     throw new ControlLoopException("The target type is not supported");
160                 }
161             }
162             else {
163                 throw new ControlLoopException("The target type is null");
164             }
165         }
166         else {
167             throw new ControlLoopException("The target is null");
168         }
169         throw new ControlLoopException("Target does not match target type");
170     }
171         
172         public ControlLoopOperationManager(ControlLoopEvent onset, Policy policy, ControlLoopEventManager em) throws ControlLoopException, AAIException {
173                 this.onset = onset;
174                 this.policy = policy;
175                 this.guardApprovalStatus = "NONE";
176                 this.eventManager = em;
177                 this.targetEntity = getTarget(policy);
178                 
179                 //
180                 // Let's make a sanity check
181                 //
182                 switch (policy.getActor()) {
183                 case "APPC":
184                     if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
185                         /*
186                  * The target vnf-id may not be the same as the source vnf-id
187                  * specified in the yaml, the target vnf-id is retrieved by
188                  * a named query to A&AI.
189                  */
190                         String targetVnf = AppcLcmActorServiceProvider.vnfNamedQuery(
191                                     policy.getTarget().getResourceID(), this.targetEntity);
192                         this.targetEntity = targetVnf;
193                     }
194                         break;
195                 case "SO":
196                     break;
197                 case "VFC":
198                         break;
199                 default:
200                         throw new ControlLoopException("ControlLoopEventManager: policy has an unknown actor.");
201                 }
202         }
203
204         public Object startOperation(/*VirtualControlLoopEvent*/ControlLoopEvent onset) throws AAIException {
205                 //
206                 // They shouldn't call us if we currently running something
207                 //
208                 if (this.currentOperation != null) {
209                         //
210                         // what do we do if we are already running an operation?
211                         //
212                         return null;
213                 }
214                 //
215                 // Check if we have maxed out on retries
216                 //
217                 if (this.policy.getRetry() == null || this.policy.getRetry() < 1) {
218                         //
219                         // No retries are allowed, so check have we even made
220                         // one attempt to execute the operation?
221                         //
222                         if (this.attempts >= 1) {
223                                 //
224                                 // We have, let's ensure our PolicyResult is set
225                                 //
226                                 if (this.policyResult == null) {
227                                         this.policyResult = PolicyResult.FAILURE_RETRIES;
228                                 }
229                                 //
230                                 //
231                                 //
232                                 return null;
233                         }
234                 } else {
235                         //
236                         // Have we maxed out on retries?
237                         //
238                         if (this.attempts > this.policy.getRetry()) {
239                                 if (this.policyResult == null) {
240                                         this.policyResult = PolicyResult.FAILURE_RETRIES;
241                                 }
242                                 return null;
243                         }
244                 }
245                 //
246                 // Setup
247                 //
248                 this.policyResult = null;
249                 Operation operation = new Operation();
250                 operation.attempt = ++this.attempts;
251                 operation.operation.actor = this.policy.getActor();
252                 operation.operation.operation = this.policy.getRecipe();
253                 operation.operation.target = this.policy.getTarget().toString();
254                 operation.operation.subRequestId = Integer.toString(operation.attempt);
255                 //
256                 // Now determine which actor we need to construct a request for
257                 //
258                 switch (policy.getActor()) {
259                 case "APPC":
260                     /*
261                      * If the recipe is ModifyConfig, a legacy APPC
262                      * request is constructed. Otherwise an LCMRequest
263                      * is constructed.
264                      */
265                         this.currentOperation = operation;
266                     if ("ModifyConfig".equalsIgnoreCase(policy.getRecipe())) {
267
268                     this.operationRequest = APPCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, 
269                                             operation.operation, this.policy, this.targetEntity);
270                     }
271                     else {
272                         this.operationRequest = AppcLcmActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, 
273                                                 operation.operation, this.policy, this.targetEntity);
274                     }
275                         //
276                         // Save the operation
277                         //
278                         
279                         return operationRequest;
280                 case "SO":
281                         SOActorServiceProvider SOAsp = new SOActorServiceProvider();
282                         this.operationRequest = SOAsp.constructRequest((VirtualControlLoopEvent)onset, operation.operation, this.policy);
283
284                         // Save the operation
285                         this.currentOperation = operation;
286
287                         if (this.operationRequest == null) {
288                                 this.policyResult = PolicyResult.FAILURE;
289                         }
290
291                         return operationRequest;
292                 case "VFC":
293             this.operationRequest = VFCActorServiceProvider.constructRequest((VirtualControlLoopEvent) onset, operation.operation, this.policy, this.eventManager.getVnfResponse());
294             this.currentOperation = operation;
295             if (this.operationRequest == null) {
296                 this.policyResult = PolicyResult.FAILURE;
297             }
298             return operationRequest;
299
300                 }
301                 return null;
302         }
303
304         public PolicyResult     onResponse(Object response) {
305                 //
306                 // Which response is it?
307                 //
308                 if (response instanceof Response) {
309                         //
310                         // Cast it
311                         //
312                         Response appcResponse = (Response) response;
313                         //
314                         // Determine which subrequestID (ie. attempt)
315                         //
316                         Integer operationAttempt = null;
317                         try {
318                                 operationAttempt = Integer.parseInt(appcResponse.CommonHeader.SubRequestID);
319                         } catch (NumberFormatException e) {
320                                 //
321                                 // We cannot tell what happened if this doesn't exist
322                                 //
323                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
324                                 return PolicyResult.FAILURE_EXCEPTION;
325                         }
326                         //
327                         // Sanity check the response message
328                         //
329                         if (appcResponse.Status == null) {
330                                 //
331                                 // We cannot tell what happened if this doesn't exist
332                                 //
333                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status field (it was null).", PolicyResult.FAILURE_EXCEPTION);
334                                 return PolicyResult.FAILURE_EXCEPTION;
335                         }
336                         //
337                         // Get the Response Code
338                         //
339                         ResponseCode code = ResponseCode.toResponseCode(appcResponse.Status.Code);
340                         if (code == null) {
341                                 //
342                                 // We are unaware of this code
343                                 //
344                                 this.completeOperation(operationAttempt, "Policy was unable to parse APP-C response status code field.", PolicyResult.FAILURE_EXCEPTION);
345                                 return PolicyResult.FAILURE_EXCEPTION;
346                         }
347                         //
348                         // Ok, let's figure out what APP-C's response is
349                         //
350                         switch (code) {
351                         case ACCEPT:
352                                 //
353                                 // This is good, they got our original message and
354                                 // acknowledged it.
355                                 //
356                                 // Is there any need to track this?
357                                 //
358                                 return null;
359                         case ERROR:
360                         case REJECT:
361                                 //
362                                 // We'll consider these two codes as exceptions
363                                 //
364                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE_EXCEPTION);
365                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
366                                         return null;
367                                 }
368                                 return PolicyResult.FAILURE_EXCEPTION;
369                         case SUCCESS:
370                                 //
371                                 //
372                                 //
373                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.SUCCESS);
374                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
375                                         return null;
376                                 }
377                                 return PolicyResult.SUCCESS;
378                         case FAILURE:
379                                 //
380                                 //
381                                 //
382                                 this.completeOperation(operationAttempt, appcResponse.getStatus().Description, PolicyResult.FAILURE);
383                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
384                                         return null;
385                                 }
386                                 return PolicyResult.FAILURE;
387                         }
388                 }
389                 else if (response instanceof LCMResponseWrapper) {
390
391                     LCMResponseWrapper dmaapResponse = (LCMResponseWrapper) response;
392
393                     /*
394                      * Parse out the operation attempt using the subrequestid
395                      */
396                     Integer operationAttempt = AppcLcmActorServiceProvider.parseOperationAttempt(dmaapResponse.getBody().getCommonHeader().getSubRequestId());
397                     if (operationAttempt == null) {
398                         this.completeOperation(operationAttempt, "Policy was unable to parse APP-C SubRequestID (it was null).", PolicyResult.FAILURE_EXCEPTION);
399                     }
400
401                     /*
402                      * Process the APPCLCM response to see what PolicyResult
403                      * should be returned
404                      */
405                     AbstractMap.SimpleEntry<PolicyResult, String> result = AppcLcmActorServiceProvider.processResponse(dmaapResponse);
406
407                     if (result.getKey() != null) {
408                     this.completeOperation(operationAttempt, result.getValue(), result.getKey());
409                     if (PolicyResult.FAILURE_TIMEOUT.equals(this.policyResult)) {
410                     return null;
411                 }
412                     return result.getKey();
413                     }
414                     return null;
415                 } else if (response instanceof SOResponse) {
416                         SOResponse msoResponse = (SOResponse) response;
417
418                         switch (msoResponse.httpResponseCode) {
419                         case 200:
420                         case 202:
421                                 //
422                                 // Consider it as success
423                                 //
424                                 this.completeOperation(this.attempts, msoResponse.httpResponseCode + " Success", PolicyResult.SUCCESS);
425                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
426                                         return null;
427                                 }
428                                 return PolicyResult.SUCCESS;
429                         default:
430                                 //
431                                 // Consider it as failure
432                                 //
433                                 this.completeOperation(this.attempts, msoResponse.httpResponseCode + " Failed", PolicyResult.FAILURE);
434                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
435                                         return null;
436                                 }
437                                 return PolicyResult.FAILURE;
438                         }
439
440                 } else if (response instanceof VFCResponse) {
441                         VFCResponse vfcResponse = (VFCResponse) response;
442
443                         if (vfcResponse.responseDescriptor.getStatus().equalsIgnoreCase("finished")) {
444                                 //
445                                 // Consider it as success
446                                 //
447                                 this.completeOperation(this.attempts, " Success", PolicyResult.SUCCESS);
448                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
449                                         return null;
450                                 }
451                                 return PolicyResult.SUCCESS;
452                         } else {
453                                 //
454                                 // Consider it as failure
455                                 //
456                                 this.completeOperation(this.attempts, " Failed", PolicyResult.FAILURE);
457                                 if (this.policyResult != null && this.policyResult.equals(PolicyResult.FAILURE_TIMEOUT)) {
458                                         return null;
459                                 }
460                                 // increment operation attempts for retries
461                                 this.attempts += 1;
462                                 return PolicyResult.FAILURE;
463                         }
464                 }
465                 return null;
466         }
467
468         public Integer  getOperationTimeout() {
469                 //
470                 // Sanity check
471                 //
472                 if (this.policy == null) {
473                         logger.debug("getOperationTimeout returning 0");
474                         return 0;
475                 }
476                 logger.debug("getOperationTimeout returning {}", this.policy.getTimeout());
477                 return this.policy.getTimeout();
478         }
479
480         public String   getOperationTimeoutString(int defaultTimeout) {
481                 Integer to = this.getOperationTimeout();
482                 if (to == null || to == 0) {
483                         return Integer.toString(defaultTimeout) + "s";
484                 }
485                 return to.toString() + "s";
486         }
487
488         public PolicyResult     getOperationResult() {
489                 return this.policyResult;
490         }
491
492         public String   getOperationMessage() {
493                 if (this.currentOperation != null && this.currentOperation.operation != null) {
494                         return this.currentOperation.operation.toMessage();
495                 }
496
497                 if (!this.operationHistory.isEmpty()) {
498                         return this.operationHistory.getLast().operation.toMessage();
499                 }
500                 return null;
501         }
502
503         public String   getOperationMessage(String guardResult) {
504                 if (this.currentOperation != null && this.currentOperation.operation != null) {
505                         return this.currentOperation.operation.toMessage()+ ", Guard result: " + guardResult;
506                 }
507           
508                 if (!this.operationHistory.isEmpty()) {
509                         return this.operationHistory.getLast().operation.toMessage() + ", Guard result: " + guardResult;
510                 }
511                 return null;
512         }
513
514         public String   getOperationHistory() {
515                 if (this.currentOperation != null && this.currentOperation.operation != null) {
516                         return this.currentOperation.operation.toHistory();
517                 }
518           
519                 if (!this.operationHistory.isEmpty()) {
520                         return this.operationHistory.getLast().operation.toHistory();
521                 }
522                 return null;
523         }
524
525         public LinkedList<ControlLoopOperation> getHistory() {
526                 LinkedList<ControlLoopOperation> history = new LinkedList<ControlLoopOperation>();
527                 for (Operation op : this.operationHistory) {
528                         history.add(new ControlLoopOperation(op.operation));
529
530                 }
531                 return history;
532         }
533
534         public void             setOperationHasTimedOut() {
535                 //
536                 //
537                 //
538                 this.completeOperation(this.attempts, "Operation timed out", PolicyResult.FAILURE_TIMEOUT);
539         }
540
541         public void             setOperationHasGuardDeny() {
542                 //
543                 //
544                 //
545                 this.completeOperation(this.attempts, "Operation denied by Guard", PolicyResult.FAILURE_GUARD);
546         }
547         
548         public void setOperationHasException(String message) {
549                 this.completeOperation(this.attempts, message, PolicyResult.FAILURE_EXCEPTION);
550         }
551
552         public boolean  isOperationComplete() {
553                 //
554                 // Is there currently a result?
555                 //
556                 if (this.policyResult == null) {
557                         //
558                         // either we are in process or we
559                         // haven't started
560                         //
561                         return false;
562                 }
563                 //
564                 // We have some result, check if the operation failed
565                 //
566                 if (this.policyResult.equals(PolicyResult.FAILURE)) {
567                         //
568                         // Check if there were no retries specified
569                         //
570                         if (policy.getRetry() == null || policy.getRetry() == 0) {
571                                 //
572                                 // The result is the failure
573                                 //
574                                 return true;
575                         }
576                         //
577                         // Check retries
578                         //
579                         if (this.isRetriesMaxedOut()) {
580                                 //
581                                 // No more attempts allowed, reset
582                                 // that our actual result is failure due to retries
583                                 //
584                                 this.policyResult = PolicyResult.FAILURE_RETRIES;
585                                 return true;
586                         } else {
587                                 //
588                                 // There are more attempts available to try the
589                                 // policy recipe.
590                                 //
591                                 return false;
592                         }
593                 }
594                 //
595                 // Other results mean we are done
596                 //
597                 return true;
598         }
599
600         public boolean  isOperationRunning() {
601                 return (this.currentOperation != null);
602         }
603
604         private boolean isRetriesMaxedOut() {
605                 if (policy.getRetry() == null || policy.getRetry() == 0) {
606                         //
607                         // There were NO retries specified, so declare
608                         // this as completed.
609                         //
610                         return (this.attempts > 0);
611                 }
612                 return (this.attempts > policy.getRetry());
613         }
614
615         private void    storeOperationInDataBase(){
616                 // Only store in DB if enabled
617                 boolean guardEnabled = "false".equalsIgnoreCase(PolicyEngine.manager.getEnvironmentProperty("guard.disabled"));
618                 if( !guardEnabled ){
619                         return;
620                 }
621
622
623                 // DB Properties
624                 Properties props = new Properties();
625                 if(PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL) != null &&
626                                 PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER) != null &&
627                                 PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS) != null){
628                         props.put(Util.ECLIPSE_LINK_KEY_URL, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_URL));
629                         props.put(Util.ECLIPSE_LINK_KEY_USER, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_USER));
630                         props.put(Util.ECLIPSE_LINK_KEY_PASS, PolicyEngine.manager.getEnvironmentProperty(Util.ONAP_KEY_PASS));
631                         props.put(PersistenceUnitProperties.CLASSLOADER, ControlLoopOperationManager.class.getClassLoader());
632                 }
633                 
634                 
635                 String OpsHistPU = System.getProperty("OperationsHistoryPU");
636                 if(OpsHistPU == null || !OpsHistPU.equals("TestOperationsHistoryPU")){
637                         OpsHistPU = "OperationsHistoryPU";
638                 }
639                 else{
640                         props.clear();
641                 }
642                 EntityManager em;
643                 try{
644                         em = Persistence.createEntityManagerFactory(OpsHistPU, props).createEntityManager();
645                 }catch(Exception e){
646                         logger.error("storeOperationInDataBase threw: ", e);
647                         return;
648                 }
649
650                 OperationsHistoryDbEntry newEntry = new OperationsHistoryDbEntry();
651
652                 newEntry.closedLoopName = this.onset.closedLoopControlName;
653                 newEntry.requestId = this.onset.requestID.toString();
654                 newEntry.actor = this.currentOperation.operation.actor;
655                 newEntry.operation = this.currentOperation.operation.operation;
656                 newEntry.target = this.targetEntity;
657                 newEntry.starttime = Timestamp.from(this.currentOperation.operation.start);
658                 newEntry.subrequestId = this.currentOperation.operation.subRequestId;
659                 newEntry.endtime = new Timestamp(this.currentOperation.operation.end.toEpochMilli());
660                 newEntry.message = this.currentOperation.operation.message;
661                 newEntry.outcome = this.currentOperation.operation.outcome;
662
663                 em.getTransaction().begin();
664                 em.persist(newEntry);
665                 em.getTransaction().commit();
666
667                 em.close();
668
669         }
670
671
672
673         private void    completeOperation(Integer attempt, String message, PolicyResult result) {
674                 if (attempt == null) {
675                         logger.debug("attempt cannot be null (i.e. subRequestID)");
676                         return;
677                 }
678                 if (this.currentOperation != null) {
679                         if (this.currentOperation.attempt == attempt.intValue()) {
680                                 this.currentOperation.operation.end = Instant.now();
681                                 this.currentOperation.operation.message = message;
682                                 this.currentOperation.operation.outcome = result.toString();
683                                 this.currentOperation.policyResult = result;
684                                 //
685                                 // Save it in history
686                                 //
687                                 this.operationHistory.add(this.currentOperation);
688                                 this.storeOperationInDataBase();
689                                 //
690                                 // Set our last result
691                                 //
692                                 this.policyResult = result;
693                                 //
694                                 // Clear the current operation field
695                                 //
696                                 this.currentOperation = null;
697                                 return;
698                         }
699                         logger.debug("not current");
700                 }
701                 for (Operation op : this.operationHistory) {
702                         if (op.attempt == attempt.intValue()) {
703                                 op.operation.end = Instant.now();
704                                 op.operation.message = message;
705                                 op.operation.outcome = result.toString();
706                                 op.policyResult = result;
707                                 return;
708                         }
709                 }
710                 logger.debug("Could not find associated operation");
711
712         }
713
714 }