0aa6f2a796844888cace5ade0f490e0d858110d3
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-yaml
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.compiler;
22
23 import java.io.InputStream;
24 import java.io.Serializable;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Map.Entry;
30
31 import org.jgrapht.DirectedGraph;
32 import org.jgrapht.graph.ClassBasedEdgeFactory;
33 import org.jgrapht.graph.DefaultEdge;
34 import org.jgrapht.graph.DirectedMultigraph;
35 import org.onap.policy.controlloop.policy.ControlLoop;
36 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
37 import org.onap.policy.controlloop.policy.FinalResult;
38 import org.onap.policy.controlloop.policy.Policy;
39 import org.onap.policy.controlloop.policy.PolicyResult;
40 import org.onap.policy.controlloop.policy.TargetType;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43 import org.yaml.snakeyaml.Yaml;
44 import org.yaml.snakeyaml.constructor.Constructor;
45
46 import com.google.common.collect.ImmutableList;
47 import com.google.common.collect.ImmutableMap;
48
49 public class ControlLoopCompiler implements Serializable{
50     private static final String OPERATION_POLICY = "Operation Policy ";
51         private static final long serialVersionUID = 1L;
52     private static final Logger LOGGER = LoggerFactory.getLogger(ControlLoopCompiler.class.getName());
53     
54     public static ControlLoopPolicy compile(ControlLoopPolicy policy, ControlLoopCompilerCallback callback) throws CompilerException {
55         //
56         // Ensure the control loop is sane
57         //
58         validateControlLoop(policy.getControlLoop(), callback);
59         //
60         // Validate the policies
61         //
62         validatePolicies(policy, callback);
63         
64         return policy;
65     }
66     
67     public static ControlLoopPolicy compile(InputStream yamlSpecification, ControlLoopCompilerCallback callback) throws CompilerException {
68         Yaml yaml = new Yaml(new Constructor(ControlLoopPolicy.class));
69         Object obj = yaml.load(yamlSpecification);
70         if (obj == null) {
71             throw new CompilerException("Could not parse yaml specification.");
72         }
73         if (! (obj instanceof ControlLoopPolicy)) {
74             throw new CompilerException("Yaml could not parse specification into required ControlLoopPolicy object");
75         }
76         return ControlLoopCompiler.compile((ControlLoopPolicy) obj, callback);
77     }
78     
79     private static void validateControlLoop(ControlLoop controlLoop, ControlLoopCompilerCallback callback) throws CompilerException {
80         if (controlLoop == null && callback != null) {
81             callback.onError("controlLoop cannot be null");
82         }
83         if (controlLoop!=null){
84             if ((controlLoop.getControlLoopName() == null || controlLoop.getControlLoopName().length() < 1) && callback != null) {
85                 callback.onError("Missing controlLoopName");
86             }
87             if ((!controlLoop.getVersion().contentEquals(ControlLoop.getVERSION())) && callback != null) {
88                 callback.onError("Unsupported version for this compiler");
89             }
90             if (controlLoop.getTrigger_policy() == null || controlLoop.getTrigger_policy().length() < 1) {
91                 throw new CompilerException("trigger_policy is not valid");
92             }
93         }
94     }
95
96     private static void validatePolicies(ControlLoopPolicy policy, ControlLoopCompilerCallback callback) throws CompilerException {
97         if (policy == null) {
98             throw new CompilerException("policy cannot be null");
99         }
100         if (policy.getPolicies() == null) {
101             callback.onWarning("controlLoop is an open loop.");   
102         }
103         else{
104             //
105             // For this version we can use a directed multigraph, in the future we may not be able to
106             //
107             DirectedGraph<NodeWrapper, LabeledEdge> graph = new DirectedMultigraph<>(new ClassBasedEdgeFactory<NodeWrapper, LabeledEdge>(LabeledEdge.class));
108             //
109             // Check to see if the trigger Event is for OpenLoop, we do so by
110             // attempting to create a FinalResult object from it. If its a policy id, this should
111             // return null.
112             //
113             FinalResult triggerResult = FinalResult.toResult(policy.getControlLoop().getTrigger_policy());
114             TriggerNodeWrapper triggerNode;
115             //
116             // Did this turn into a FinalResult object?
117             //
118             if (triggerResult != null) {
119                 validateOpenLoopPolicy(policy, triggerResult, callback);
120                 return;
121                 //
122             } else {
123                 validatePoliciesContainTriggerPolicyAndCombinedTimeoutIsOk(policy, callback);
124                 triggerNode = new TriggerNodeWrapper(policy.getControlLoop().getControlLoopName());
125             }
126             //
127             // Add in the trigger node
128             //
129             graph.addVertex(triggerNode);
130             //
131             // Add in our Final Result nodes. All paths should end to these nodes.
132             //
133             FinalResultNodeWrapper finalSuccess = new FinalResultNodeWrapper(FinalResult.FINAL_SUCCESS);
134             FinalResultNodeWrapper finalFailure = new FinalResultNodeWrapper(FinalResult.FINAL_FAILURE);
135             FinalResultNodeWrapper finalFailureTimeout = new FinalResultNodeWrapper(FinalResult.FINAL_FAILURE_TIMEOUT);
136             FinalResultNodeWrapper finalFailureRetries = new FinalResultNodeWrapper(FinalResult.FINAL_FAILURE_RETRIES);
137             FinalResultNodeWrapper finalFailureException = new FinalResultNodeWrapper(FinalResult.FINAL_FAILURE_EXCEPTION);
138             FinalResultNodeWrapper finalFailureGuard = new FinalResultNodeWrapper(FinalResult.FINAL_FAILURE_GUARD);
139             graph.addVertex(finalSuccess);
140             graph.addVertex(finalFailure);
141             graph.addVertex(finalFailureTimeout);
142             graph.addVertex(finalFailureRetries);
143             graph.addVertex(finalFailureException);
144             graph.addVertex(finalFailureGuard);
145             //
146             // Work through the policies and add them in as nodes.
147             //
148             Map<Policy, PolicyNodeWrapper> mapNodes = addPoliciesAsNodes(policy, graph, triggerNode, callback);
149             //
150             // last sweep to connect remaining edges for policy results
151             //
152             for (Policy operPolicy : policy.getPolicies()) {
153                 PolicyNodeWrapper node = mapNodes.get(operPolicy);
154                 //
155                 // Just ensure this has something
156                 //
157                 if (node == null) {
158                     continue;
159                 }
160                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getSuccess(), finalSuccess, PolicyResult.SUCCESS, node);
161                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getFailure(), finalFailure, PolicyResult.FAILURE, node);
162                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getFailure_timeout(), finalFailureTimeout, PolicyResult.FAILURE_TIMEOUT, node);
163                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getFailure_retries(), finalFailureRetries, PolicyResult.FAILURE_RETRIES, node);
164                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getFailure_exception(), finalFailureException, PolicyResult.FAILURE_EXCEPTION, node);
165                 addEdge(graph, mapNodes, operPolicy.getId(), operPolicy.getFailure_guard(), finalFailureGuard, PolicyResult.FAILURE_GUARD, node);
166             }
167             validateNodesAndEdges(graph, callback);
168         }   
169     }
170     
171     private static void validateOpenLoopPolicy(ControlLoopPolicy policy, FinalResult triggerResult, ControlLoopCompilerCallback callback) throws CompilerException{
172         //
173         // Ensure they didn't use some other FinalResult code
174         //
175         if (triggerResult != FinalResult.FINAL_OPENLOOP) {
176             throw new CompilerException("Unexpected Final Result for trigger_policy, should only be " + FinalResult.FINAL_OPENLOOP.toString() + " or a valid Policy ID");
177         }
178         //
179         // They really shouldn't have any policies attached.
180         //
181         if ((policy.getPolicies() != null || policy.getPolicies().isEmpty())&& callback != null ) {
182             callback.onWarning("Open Loop policy contains policies. The policies will never be invoked.");
183         }
184     }
185     
186     private static void validatePoliciesContainTriggerPolicyAndCombinedTimeoutIsOk(ControlLoopPolicy policy, ControlLoopCompilerCallback callback) throws CompilerException{
187         int sum = 0;
188         boolean triggerPolicyFound = false;
189         for (Policy operPolicy : policy.getPolicies()) {
190             sum += operPolicy.getTimeout().intValue();
191             if (policy.getControlLoop().getTrigger_policy().equals(operPolicy.getId())){
192                 triggerPolicyFound = true;
193             }
194         }
195         if (policy.getControlLoop().getTimeout().intValue() < sum && callback != null) {
196             callback.onError("controlLoop overall timeout is less than the sum of operational policy timeouts.");
197         }
198         
199         if (!triggerPolicyFound){
200             throw new CompilerException("Unexpected value for trigger_policy, should only be " + FinalResult.FINAL_OPENLOOP.toString() + " or a valid Policy ID");
201         }
202     }
203     
204     private static Map<Policy, PolicyNodeWrapper> addPoliciesAsNodes(ControlLoopPolicy policy, 
205             DirectedGraph<NodeWrapper, LabeledEdge> graph, TriggerNodeWrapper triggerNode, ControlLoopCompilerCallback callback){
206         Map<Policy, PolicyNodeWrapper> mapNodes = new HashMap<>();
207         for (Policy operPolicy : policy.getPolicies()) {
208             //
209             // Is it still ok to add?
210             //
211             if (!okToAdd(operPolicy, callback)) {
212                 //
213                 // Do not add it in
214                 //
215                 continue;
216             }
217             //
218             // Create wrapper policy node and save it into our map so we can
219             // easily retrieve it.
220             //
221             PolicyNodeWrapper node = new PolicyNodeWrapper(operPolicy);
222             mapNodes.put(operPolicy, node);
223             graph.addVertex(node);
224             //
225             // Is this the trigger policy?
226             //
227             if (operPolicy.getId().equals(policy.getControlLoop().getTrigger_policy())) {
228                 //
229                 // Yes add an edge from our trigger event node to this policy
230                 //
231                 graph.addEdge(triggerNode, node, new LabeledEdge(triggerNode, node, new TriggerEdgeWrapper("ONSET")));
232             }
233         }
234         return mapNodes;
235     }
236     
237     private static void addEdge(DirectedGraph<NodeWrapper, LabeledEdge> graph, Map<Policy, PolicyNodeWrapper> mapNodes, String policyId, String connectedPolicy, 
238             FinalResultNodeWrapper finalResultNodeWrapper, PolicyResult policyResult, NodeWrapper node) throws CompilerException{
239         FinalResult finalResult = FinalResult.toResult(finalResultNodeWrapper.getID());
240         if (FinalResult.isResult(connectedPolicy, finalResult)) {
241             graph.addEdge(node, finalResultNodeWrapper, new LabeledEdge(node, finalResultNodeWrapper, new FinalResultEdgeWrapper(finalResult)));
242         } else {
243             PolicyNodeWrapper toNode = findPolicyNode(mapNodes, connectedPolicy);
244             if (toNode == null) {
245                 throw new CompilerException(OPERATION_POLICY + policyId + " is connected to unknown policy " + connectedPolicy);
246             } else {
247                 graph.addEdge(node, toNode, new LabeledEdge(node, toNode, new PolicyResultEdgeWrapper(policyResult)));
248             }
249         }
250     }
251     
252     private static void validateNodesAndEdges(DirectedGraph<NodeWrapper, LabeledEdge> graph, ControlLoopCompilerCallback callback) throws CompilerException{
253         for (NodeWrapper node : graph.vertexSet()) {
254             if (node instanceof TriggerNodeWrapper) {
255                 validateTriggerNodeWrapper(graph, node);
256             } else if (node instanceof FinalResultNodeWrapper) {
257                 validateFinalResultNodeWrapper(graph, node);
258             } else if (node instanceof PolicyNodeWrapper) {
259                 validatePolicyNodeWrapper(graph, node, callback);
260             }
261             for (LabeledEdge edge : graph.outgoingEdgesOf(node)){
262                 LOGGER.info(edge.from.getID() + " invokes " + edge.to.getID() + " upon " + edge.edge.getID());
263             }
264         }
265     }
266     
267     private static void validateTriggerNodeWrapper(DirectedGraph<NodeWrapper, LabeledEdge> graph, NodeWrapper node) throws CompilerException{
268         if (LOGGER.isDebugEnabled()) {
269             LOGGER.info("Trigger Node {}", node.toString());
270         }
271         if (graph.inDegreeOf(node) > 0 ) {
272             //
273             // Really should NEVER get here unless someone messed up the code above.
274             //
275             throw new CompilerException("No inputs to event trigger");
276         }
277         //
278         // Should always be 1, except in the future we may support multiple events
279         //
280         if (graph.outDegreeOf(node) > 1) {
281             throw new CompilerException("The event trigger should only go to ONE node");
282         }
283     }
284     
285     private static void validateFinalResultNodeWrapper(DirectedGraph<NodeWrapper, LabeledEdge> graph, NodeWrapper node) throws CompilerException{
286         if (LOGGER.isDebugEnabled()) {
287             LOGGER.info("FinalResult Node {}", node.toString());
288         }
289         //
290         // FinalResult nodes should NEVER have an out edge
291         //
292         if (graph.outDegreeOf(node) > 0) {
293             throw new CompilerException("FinalResult nodes should never have any out edges.");
294         }
295     }
296     
297     private static void validatePolicyNodeWrapper(DirectedGraph<NodeWrapper, LabeledEdge> graph, NodeWrapper node, ControlLoopCompilerCallback callback) throws CompilerException{
298         if (LOGGER.isDebugEnabled()) {
299             LOGGER.info("Policy Node {}", node.toString());
300         }
301         //
302         // All Policy Nodes should have the 5 out degrees defined.
303         //
304         if (graph.outDegreeOf(node) != 6) {
305             throw new CompilerException("Policy node should ALWAYS have 6 out degrees.");
306         }
307         //
308         // All Policy Nodes should have at least 1 in degrees 
309         // 
310         if (graph.inDegreeOf(node) == 0 && callback != null) {
311             callback.onWarning("Policy " + node.getID() + " is not reachable.");
312         }
313     }
314     
315     private static boolean okToAdd(Policy operPolicy, ControlLoopCompilerCallback callback) {
316         boolean isOk = isPolicyIdOk(operPolicy, callback);
317         isOk = isActorOk(operPolicy, callback) ? isOk : false;
318         isOk = isRecipeOk(operPolicy, callback) ? isOk : false;
319         isOk = isTargetOk(operPolicy, callback) ? isOk : false;
320         isOk = arePolicyResultsOk(operPolicy, callback) ? isOk : false;
321         return isOk;
322     }
323     
324     private static boolean isPolicyIdOk(Policy operPolicy, ControlLoopCompilerCallback callback) {
325         boolean isOk = true;
326         if (operPolicy.getId() == null || operPolicy.getId().length() < 1) {
327             if (callback != null) {
328                 callback.onError("Operational Policy has an bad ID");
329             }
330             isOk = false;
331         } else {
332             //
333             // Check if they decided to make the ID a result object
334             //
335             if (PolicyResult.toResult(operPolicy.getId()) != null) {
336                 if (callback != null) {
337                     callback.onError("Policy id is set to a PolicyResult " + operPolicy.getId());
338                 }
339                 isOk = false;
340             }
341             if (FinalResult.toResult(operPolicy.getId()) != null) {
342                 if (callback != null) {
343                     callback.onError("Policy id is set to a FinalResult " + operPolicy.getId());
344                 }
345                 isOk = false;
346             }
347         }
348         return isOk;
349     }
350     
351     private static boolean isActorOk(Policy operPolicy, ControlLoopCompilerCallback callback) {
352         boolean isOk = true;
353         if (operPolicy.getActor() == null) {
354             if (callback != null) {
355                 callback.onError("Policy actor is null");
356             }
357             isOk = false;
358         }
359         //
360         // Construct a list for all valid actors
361         //
362         ImmutableList<String> actors = ImmutableList.of("APPC", "AOTS", "MSO", "SDNO", "SDNR", "AAI");
363         //
364         if (operPolicy.getActor() != null && (!actors.contains(operPolicy.getActor())) ) {
365             if (callback != null) {
366                 callback.onError("Policy actor is invalid");
367             }
368             isOk = false;
369         }
370         return isOk;
371     }
372     
373     private static boolean isRecipeOk(Policy operPolicy, ControlLoopCompilerCallback callback) {
374         boolean isOk = true;
375         if (operPolicy.getRecipe() == null) {
376             if (callback != null) {
377                 callback.onError("Policy recipe is null");
378             }
379             isOk = false;
380         }
381         //
382         // NOTE: We need a way to find the acceptable recipe values (either Enum or a database that has these)
383         // 
384         ImmutableMap<String, List<String>> recipes = new ImmutableMap.Builder<String, List<String>>()
385                 .put("APPC", ImmutableList.of("Restart", "Rebuild", "Migrate", "ModifyConfig"))
386                 .put("AOTS", ImmutableList.of("checkMaintenanceWindow", "checkENodeBTicketHours", "checkEquipmentStatus", "checkEimStatus", "checkEquipmentMaintenance"))
387                 .put("MSO", ImmutableList.of("VF Module Create"))
388                 .put("SDNO", ImmutableList.of("health-diagnostic-type", "health-diagnostic", "health-diagnostic-history", "health-diagnostic-commands", "health-diagnostic-aes"))
389                 .put("SDNR", ImmutableList.of("Restart", "Reboot"))
390                 .build();
391         //
392         if (operPolicy.getRecipe() != null && (!recipes.getOrDefault(operPolicy.getActor(), Collections.emptyList()).contains(operPolicy.getRecipe()))) {
393             if (callback != null) {
394                 callback.onError("Policy recipe is invalid");
395             }
396             isOk = false;
397         }
398         return isOk;
399     }
400     
401     private static boolean isTargetOk(Policy operPolicy, ControlLoopCompilerCallback callback) {
402         boolean isOk = true;
403         if (operPolicy.getTarget() == null) {
404             if (callback != null) {
405                 callback.onError("Policy target is null");
406             }
407             isOk = false;
408         }
409         if (operPolicy.getTarget() != null && operPolicy.getTarget().getType() != TargetType.VM && operPolicy.getTarget().getType() != TargetType.VFC && operPolicy.getTarget().getType() != TargetType.PNF) {
410             if (callback != null) {
411                 callback.onError("Policy target is invalid");
412             }
413             isOk = false;
414         }
415         return isOk;
416     }
417     
418     private static boolean arePolicyResultsOk(Policy operPolicy, ControlLoopCompilerCallback callback) {
419         //
420         // Check that policy results are connected to either default final * or another policy
421         //
422         boolean isOk = isSuccessPolicyResultOk(operPolicy, callback);
423         isOk = isFailurePolicyResultOk(operPolicy, callback) ? isOk : false;
424         isOk = isFailureRetriesPolicyResultOk(operPolicy, callback) ? isOk : false;
425         isOk = isFailureTimeoutPolicyResultOk(operPolicy, callback) ? isOk : false;
426         isOk = isFailureExceptionPolicyResultOk(operPolicy, callback) ? isOk : false;
427         isOk = isFailureGuardPolicyResultOk(operPolicy, callback) ? isOk : false;
428         return isOk;
429     }
430     
431     private static boolean isSuccessPolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
432         boolean isOk = true;
433         if (FinalResult.toResult(operPolicy.getSuccess()) != null && !operPolicy.getSuccess().equals(FinalResult.FINAL_SUCCESS.toString())) {
434             if (callback != null) {
435                 callback.onError("Policy success is neither another policy nor FINAL_SUCCESS");
436             }
437             isOk = false;
438         }
439         return isOk;
440     }
441     
442     private static boolean isFailurePolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
443         boolean isOk = true;
444         if (FinalResult.toResult(operPolicy.getFailure()) != null && !operPolicy.getFailure().equals(FinalResult.FINAL_FAILURE.toString())) {
445             if (callback != null) {
446                 callback.onError("Policy failure is neither another policy nor FINAL_FAILURE");
447             }
448             isOk = false;
449         }
450         return isOk;
451     }
452     
453     private static boolean isFailureRetriesPolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
454         boolean isOk = true;
455         if (FinalResult.toResult(operPolicy.getFailure_retries()) != null && !operPolicy.getFailure_retries().equals(FinalResult.FINAL_FAILURE_RETRIES.toString())) {
456             if (callback != null) {
457                 callback.onError("Policy failure retries is neither another policy nor FINAL_FAILURE_RETRIES");
458             }
459             isOk = false;
460         }
461         return isOk;
462     }
463     
464     private static boolean isFailureTimeoutPolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
465         boolean isOk = true;
466         if (FinalResult.toResult(operPolicy.getFailure_timeout()) != null && !operPolicy.getFailure_timeout().equals(FinalResult.FINAL_FAILURE_TIMEOUT.toString())) {
467             if (callback != null) {
468                 callback.onError("Policy failure timeout is neither another policy nor FINAL_FAILURE_TIMEOUT");
469             }
470             isOk = false;
471         }
472         return isOk;
473     }
474     
475     private static boolean isFailureExceptionPolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
476         boolean isOk = true;
477         if (FinalResult.toResult(operPolicy.getFailure_exception()) != null && !operPolicy.getFailure_exception().equals(FinalResult.FINAL_FAILURE_EXCEPTION.toString())) {
478             if (callback != null) {
479                 callback.onError("Policy failure exception is neither another policy nor FINAL_FAILURE_EXCEPTION");
480             }
481             isOk = false;
482         }
483         return isOk;
484     }
485     
486     private static boolean isFailureGuardPolicyResultOk(Policy operPolicy, ControlLoopCompilerCallback callback){
487         boolean isOk = true;
488         if (FinalResult.toResult(operPolicy.getFailure_guard()) != null && !operPolicy.getFailure_guard().equals(FinalResult.FINAL_FAILURE_GUARD.toString())) {
489             if (callback != null) {
490                 callback.onError("Policy failure guard is neither another policy nor FINAL_FAILURE_GUARD");
491             }
492             isOk = false;
493         }
494         return isOk;
495     }
496
497     private static PolicyNodeWrapper findPolicyNode(Map<Policy, PolicyNodeWrapper> mapNodes, String id) {
498         for (Entry<Policy, PolicyNodeWrapper> entry : mapNodes.entrySet()) {
499             if (entry.getKey().getId().equals(id)) {
500                 return entry.getValue();
501             }
502         }
503         return null;
504     }
505     
506     @FunctionalInterface
507     private interface NodeWrapper extends Serializable{
508         public String   getID();
509     }
510     
511     private static class TriggerNodeWrapper implements NodeWrapper {
512         private static final long serialVersionUID = -187644087811478349L;
513         private String closedLoopControlName;
514         
515         public TriggerNodeWrapper(String closedLoopControlName) {
516             this.closedLoopControlName = closedLoopControlName;
517         }
518
519         @Override
520         public String toString() {
521             return "TriggerNodeWrapper [closedLoopControlName=" + closedLoopControlName + "]";
522         }
523
524         @Override
525         public String getID() {
526             return closedLoopControlName;
527         }
528         
529     }
530         
531     private static class FinalResultNodeWrapper implements NodeWrapper {
532         private static final long serialVersionUID = 8540008796302474613L;
533         private FinalResult result;
534
535         public FinalResultNodeWrapper(FinalResult result) {
536             this.result = result;
537         }
538
539         @Override
540         public String toString() {
541             return "FinalResultNodeWrapper [result=" + result + "]";
542         }
543
544         @Override
545         public String getID() {
546             return result.toString();
547         }
548     }
549     
550     private static class PolicyNodeWrapper implements NodeWrapper {
551         private static final long serialVersionUID = 8170162175653823082L;
552         private transient Policy policy;
553         
554         public PolicyNodeWrapper(Policy operPolicy) {
555             this.policy = operPolicy;
556         }
557
558         @Override
559         public String toString() {
560             return "PolicyNodeWrapper [policy=" + policy + "]";
561         }
562
563         @Override
564         public String getID() {
565             return policy.getId();
566         }
567     }
568     
569     @FunctionalInterface
570     private interface EdgeWrapper extends Serializable{
571         public String getID();
572         
573     }
574     
575     private static class TriggerEdgeWrapper implements EdgeWrapper {
576         private static final long serialVersionUID = 2678151552623278863L;
577         private String trigger;
578         
579         public TriggerEdgeWrapper(String trigger) {
580             this.trigger = trigger;
581         }
582
583         @Override
584         public String getID() {
585             return trigger;
586         }
587
588         @Override
589         public String toString() {
590             return "TriggerEdgeWrapper [trigger=" + trigger + "]";
591         }
592         
593     }
594     
595     private static class PolicyResultEdgeWrapper implements EdgeWrapper {
596         private static final long serialVersionUID = 6078569477021558310L;
597         private PolicyResult policyResult;
598
599         public PolicyResultEdgeWrapper(PolicyResult policyResult) {
600             super();
601             this.policyResult = policyResult;
602         }
603
604         @Override
605         public String toString() {
606             return "PolicyResultEdgeWrapper [policyResult=" + policyResult + "]";
607         }
608
609         @Override
610         public String getID() {
611             return policyResult.toString();
612         }
613         
614         
615     }
616     
617     private static class FinalResultEdgeWrapper implements EdgeWrapper {
618         private static final long serialVersionUID = -1486381946896779840L;
619         private FinalResult finalResult;
620         public FinalResultEdgeWrapper(FinalResult result) {
621             this.finalResult = result;
622         }
623
624         @Override
625         public String toString() {
626             return "FinalResultEdgeWrapper [finalResult=" + finalResult + "]";
627         }
628         
629         @Override
630         public String getID() {
631             return finalResult.toString();
632         }
633     }
634     
635     
636     private static class LabeledEdge extends DefaultEdge {
637         private static final long serialVersionUID = 579384429573385524L;
638         
639         private NodeWrapper from;
640         private NodeWrapper to;
641         private EdgeWrapper edge;
642         
643         public LabeledEdge(NodeWrapper from, NodeWrapper to, EdgeWrapper edge) {
644             this.from = from;
645             this.to = to;
646             this.edge = edge;
647         }
648         
649         @SuppressWarnings("unused")
650         public NodeWrapper from() {
651             return from;
652         }
653         
654         @SuppressWarnings("unused")
655         public NodeWrapper to() {
656             return to;
657         }
658         
659         @SuppressWarnings("unused")
660         public EdgeWrapper edge() {
661             return edge;
662         }
663
664         @Override
665         public String toString() {
666             return "LabeledEdge [from=" + from + ", to=" + to + ", edge=" + edge + "]";
667         }
668     }
669
670 }