e3120db296f9690598e683a4a74e874f19d94cf6
[policy/apex-pdp.git] / model / policy-model / src / main / java / org / onap / policy / apex / model / policymodel / concepts / AxStateTree.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2016-2018 Ericsson. All rights reserved.
4  *  Modifications Copyright (C) 2019 Nordix Foundation.
5  * ================================================================================
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * SPDX-License-Identifier: Apache-2.0
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.policy.apex.model.policymodel.concepts;
23
24 import java.util.ArrayList;
25 import java.util.LinkedHashSet;
26 import java.util.List;
27 import java.util.Set;
28 import java.util.TreeSet;
29
30 import org.onap.policy.apex.model.basicmodel.concepts.AxReferenceKey;
31 import org.onap.policy.common.utils.validation.Assertions;
32
33 /**
34  * The Class is used to return the tree that represents the state branches or chains in a policy. It
35  * creates a tree that holds the state fan out branches in a policy that starts from the given top
36  * state of the tree. Each branch from a state is held in a set of next states for the top state and
37  * each branch in the state tree is itself a {@link AxStateTree} instance.
38  *
39  * <p>Validation checks for recursive state use, in other words validation forbids the use of a given
40  * state more than once in a state tree.
41  */
42 public class AxStateTree implements Comparable<AxStateTree> {
43     private final AxState thisState;
44     private final Set<AxStateTree> nextStates;
45
46     /**
47      * This constructor recursively creates a state tree for the given policy starting at the given
48      * state.
49      *
50      * @param policy the policy from which to read states
51      * @param thisState the state to start state tree construction at
52      * @param referencedStateNameSet a set of state names already referenced in the tree, null for
53      *        the first recursive call
54      */
55     public AxStateTree(final AxPolicy policy, final AxState thisState, Set<AxReferenceKey> referencedStateNameSet) {
56         Assertions.argumentNotNull(policy, "policy may not be null");
57         Assertions.argumentNotNull(thisState, "thisState may not be null");
58
59         this.thisState = thisState;
60         nextStates = new TreeSet<>();
61
62         for (final AxStateOutput stateOutput : thisState.getStateOutputs().values()) {
63             final AxState nextState = policy.getStateMap().get(stateOutput.getNextState().getLocalName());
64
65             // Check for end of state branch
66             if (stateOutput.getNextState().equals(AxReferenceKey.getNullKey())) {
67                 continue;
68             }
69
70             if (referencedStateNameSet == null) {
71                 referencedStateNameSet = new LinkedHashSet<>();
72                 referencedStateNameSet.add(thisState.getKey());
73             }
74
75             // Check for state tree loops
76             if (referencedStateNameSet.contains(nextState.getKey())) {
77                 throw new PolicyRuntimeException("loop detected in state tree for policy " + policy.getId() + " state "
78                         + thisState.getKey().getLocalName() + ", next state " + nextState.getKey().getLocalName()
79                         + " referenced more than once");
80             }
81             referencedStateNameSet.add(stateOutput.getNextState());
82             nextStates.add(new AxStateTree(policy, nextState, referencedStateNameSet));
83         }
84     }
85
86     /**
87      * Gets the state for this state tree node.
88      *
89      * @return the state
90      */
91     public AxState getState() {
92         return thisState;
93     }
94
95     /**
96      * Gets the next states for this state tree node.
97      *
98      * @return the next states
99      */
100     public Set<AxStateTree> getNextStates() {
101         return nextStates;
102     }
103
104     /**
105      * Gets the list of states referenced by this state tree as a list.
106      *
107      * @return the list of states referenced
108      */
109     public List<AxState> getReferencedStateList() {
110         final List<AxState> referencedStateList = new ArrayList<>();
111
112         referencedStateList.add(thisState);
113         for (final AxStateTree nextStateTree : nextStates) {
114             referencedStateList.addAll(nextStateTree.getReferencedStateList());
115         }
116
117         return referencedStateList;
118     }
119
120     /**
121      * Gets the list of states referenced by this state tree as a set.
122      *
123      * @return the set of states referenced
124      */
125     public Set<AxState> getReferencedStateSet() {
126         final Set<AxState> referencedStateSet = new TreeSet<>();
127
128         referencedStateSet.add(thisState);
129         for (final AxStateTree nextStateTree : nextStates) {
130             referencedStateSet.addAll(nextStateTree.getReferencedStateSet());
131         }
132
133         return referencedStateSet;
134     }
135
136     /**
137      * {@inheritDoc}.
138      */
139     @Override
140     public int compareTo(final AxStateTree otherObj) {
141         Assertions.argumentNotNull(otherObj, "comparison object may not be null");
142
143         if (this == otherObj) {
144             return 0;
145         }
146
147         final AxStateTree other = otherObj;
148         if (!thisState.equals(other.thisState)) {
149             return thisState.compareTo(other.thisState);
150         }
151         if (!nextStates.equals(other.nextStates)) {
152             return (nextStates.hashCode() - other.nextStates.hashCode());
153         }
154         return 0;
155     }
156 }