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