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