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