f1835d7408d13ba6b27619ac835845ccece3f970
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 2017-2020 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.processor;
22
23 import java.io.Serializable;
24 import java.lang.reflect.InvocationTargetException;
25 import java.net.URLDecoder;
26 import java.nio.charset.StandardCharsets;
27 import java.util.stream.Collectors;
28 import lombok.Getter;
29 import org.apache.commons.beanutils.BeanUtils;
30 import org.onap.policy.common.utils.coder.CoderException;
31 import org.onap.policy.controlloop.ControlLoopException;
32 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
33 import org.onap.policy.controlloop.policy.ControlLoop;
34 import org.onap.policy.controlloop.policy.ControlLoopPolicy;
35 import org.onap.policy.controlloop.policy.FinalResult;
36 import org.onap.policy.controlloop.policy.Policy;
37 import org.onap.policy.controlloop.policy.PolicyParam;
38 import org.onap.policy.controlloop.policy.PolicyResult;
39 import org.onap.policy.controlloop.policy.Target;
40 import org.onap.policy.controlloop.policy.TargetType;
41 import org.onap.policy.drools.domain.models.DroolsPolicy;
42 import org.onap.policy.drools.domain.models.legacy.LegacyPolicy;
43 import org.onap.policy.drools.domain.models.operational.Operation;
44 import org.onap.policy.drools.domain.models.operational.OperationalPolicy;
45 import org.onap.policy.drools.domain.models.operational.OperationalTarget;
46 import org.onap.policy.drools.system.PolicyEngineConstants;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.yaml.snakeyaml.Yaml;
51 import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
52
53 public class ControlLoopProcessor implements Serializable {
54     private static final long serialVersionUID = 1L;
55     private static final Logger logger = LoggerFactory.getLogger(ControlLoopProcessor.class);
56
57     @Getter
58     private final ControlLoopPolicy policy;
59     private String currentNestedPolicyId;
60
61     // not serializable, thus must be transient
62     @Getter
63     private transient ToscaPolicy toscaOpPolicy;
64
65     // not serializable, thus must be transient
66     @Getter
67     private transient DroolsPolicy domainOpPolicy;
68
69     /**
70      * Construct an instance from yaml.
71      *
72      * @param yaml the yaml
73      * @throws ControlLoopException if an error occurs
74      */
75     public ControlLoopProcessor(String yaml) throws ControlLoopException {
76         try {
77             final Yaml y = new Yaml(new CustomClassLoaderConstructor(ControlLoopPolicy.class,
78                     ControlLoopPolicy.class.getClassLoader()));
79             final Object obj = y.load(yaml);
80
81             this.policy = (ControlLoopPolicy) obj;
82             this.currentNestedPolicyId = this.policy.getControlLoop().getTrigger_policy();
83         } catch (final Exception e) {
84             //
85             // Most likely this is a YAML Exception
86             //
87             throw new ControlLoopException(e);
88         }
89     }
90
91     /**
92      * Create an instance from a Tosca Policy.
93      */
94     public ControlLoopProcessor(ToscaPolicy toscaPolicy) throws ControlLoopException {
95         try {
96             // TODO: automate policy type to models mapping
97             this.policy =
98                 ("onap.policies.controlloop.Operational".equals(toscaPolicy.getType()))
99                     ? buildPolicyFromToscaLegacy(toscaPolicy)
100                         : buildPolicyFromToscaCompliant(toscaPolicy);
101
102             this.currentNestedPolicyId = this.policy.getControlLoop().getTrigger_policy();
103             this.toscaOpPolicy = toscaPolicy;
104         } catch (RuntimeException | CoderException e) {
105             throw new ControlLoopException(e);
106         }
107     }
108
109     protected ControlLoopPolicy buildPolicyFromToscaLegacy(ToscaPolicy policy)
110             throws CoderException {
111         LegacyPolicy legacyPolicy =
112                 PolicyEngineConstants.getManager().getDomainMaker().convertTo(policy, LegacyPolicy.class);
113         this.domainOpPolicy = legacyPolicy;
114         String decodedPolicy = URLDecoder.decode(legacyPolicy.getProperties().getContent(), StandardCharsets.UTF_8);
115         return new Yaml(
116                 new CustomClassLoaderConstructor(
117                         ControlLoopPolicy.class, ControlLoopPolicy.class.getClassLoader())).load(decodedPolicy);
118     }
119
120     private Target toStandardTarget(OperationalTarget opTarget) {
121         Target target = new Target(TargetType.valueOf(opTarget.getTargetType()));
122         try {
123             BeanUtils.populate(target, opTarget.getEntityIds());
124         } catch (IllegalAccessException | InvocationTargetException e) {
125             logger.warn("target entityIds cannot be mapped (unexpected): {}", opTarget, e);
126         }
127         return target;
128     }
129
130     protected ControlLoopPolicy buildPolicyFromToscaCompliant(ToscaPolicy policy) throws CoderException {
131         OperationalPolicy domainPolicy =
132                 PolicyEngineConstants.getManager().getDomainMaker().convertTo(policy, OperationalPolicy.class);
133
134         ControlLoopPolicy backwardsCompatiblePolicy = new ControlLoopPolicy();
135
136         // @formatter:off
137         backwardsCompatiblePolicy.setPolicies(
138             domainPolicy.getProperties().getOperations().stream().map(this::convertPolicy)
139                     .collect(Collectors.toList()));
140         // @formatter:on
141
142         ControlLoop controlLoop = new ControlLoop();
143         controlLoop.setAbatement(domainPolicy.getProperties().isAbatement());
144         controlLoop.setControlLoopName(domainPolicy.getProperties().getId());
145         controlLoop.setTimeout(domainPolicy.getProperties().getTimeout());
146         controlLoop.setTrigger_policy(domainPolicy.getProperties().getTrigger());
147         controlLoop.setVersion(domainPolicy.getVersion());
148
149         backwardsCompatiblePolicy.setControlLoop(controlLoop);
150         this.domainOpPolicy = domainPolicy;
151         return backwardsCompatiblePolicy;
152     }
153
154     private Policy convertPolicy(Operation operation) {
155         // @formatter:off
156         Policy newPolicy = new Policy(PolicyParam.builder()
157                 .id(operation.getId())
158                 .name(operation.getActorOperation().getOperation())
159                 .description(operation.getDescription())
160                 .actor(operation.getActorOperation().getActor())
161                 .payload(operation.getActorOperation().getPayload())
162                 .recipe(operation.getActorOperation().getOperation())
163                 .retries(operation.getRetries())
164                 .timeout(operation.getTimeout())
165                 .target(toStandardTarget(operation.getActorOperation().getTarget()))
166             .build());
167         // @formatter:on
168
169         newPolicy.setSuccess(operation.getSuccess());
170         newPolicy.setFailure(operation.getFailure());
171         newPolicy.setFailure_exception(operation.getFailureException());
172         newPolicy.setFailure_guard(operation.getFailureGuard());
173         newPolicy.setFailure_retries(operation.getFailureRetries());
174         newPolicy.setFailure_timeout(operation.getFailureTimeout());
175
176         return newPolicy;
177     }
178
179     /**
180      * Get ControlLoopParams.
181      */
182     public ControlLoopParams getControlLoopParams() {
183         ControlLoopParams controlLoopParams = new ControlLoopParams();
184
185         controlLoopParams.setClosedLoopControlName(this.getControlLoop().getControlLoopName());
186         controlLoopParams.setPolicyScope(domainOpPolicy.getType() + ":" + domainOpPolicy.getTypeVersion());
187         controlLoopParams.setPolicyName(domainOpPolicy.getName());
188         controlLoopParams.setPolicyVersion(domainOpPolicy.getVersion());
189         controlLoopParams.setToscaPolicy(toscaOpPolicy);
190
191         return controlLoopParams;
192     }
193
194     public ControlLoop getControlLoop() {
195         return this.policy.getControlLoop();
196     }
197
198     public FinalResult checkIsCurrentPolicyFinal() {
199         return FinalResult.toResult(this.currentNestedPolicyId);
200     }
201
202     /**
203      * Get the current policy.
204      *
205      * @return the current policy
206      * @throws ControlLoopException if an error occurs
207      */
208     public Policy getCurrentPolicy() throws ControlLoopException {
209         if (this.policy == null || this.policy.getPolicies() == null) {
210             throw new ControlLoopException("There are no policies defined.");
211         }
212
213         for (final Policy nestedPolicy : this.policy.getPolicies()) {
214             if (nestedPolicy.getId().equals(this.currentNestedPolicyId)) {
215                 return nestedPolicy;
216             }
217         }
218         return null;
219     }
220
221     /**
222      * Get the next policy given a result of the current policy.
223      *
224      * @param result the result of the current policy
225      * @throws ControlLoopException if an error occurs
226      */
227     public void nextPolicyForResult(PolicyResult result) throws ControlLoopException {
228         final Policy currentPolicy = this.getCurrentPolicy();
229         try {
230             if (currentPolicy == null) {
231                 throw new ControlLoopException("There is no current policy to determine where to go to.");
232             }
233             switch (result) {
234                 case SUCCESS:
235                     this.currentNestedPolicyId = currentPolicy.getSuccess();
236                     break;
237                 case FAILURE:
238                     this.currentNestedPolicyId = currentPolicy.getFailure();
239                     break;
240                 case FAILURE_TIMEOUT:
241                     this.currentNestedPolicyId = currentPolicy.getFailure_timeout();
242                     break;
243                 case FAILURE_RETRIES:
244                     this.currentNestedPolicyId = currentPolicy.getFailure_retries();
245                     break;
246                 case FAILURE_EXCEPTION:
247                     this.currentNestedPolicyId = currentPolicy.getFailure_exception();
248                     break;
249                 case FAILURE_GUARD:
250                 default:
251                     this.currentNestedPolicyId = currentPolicy.getFailure_guard();
252                     break;
253             }
254         } catch (final ControlLoopException e) {
255             this.currentNestedPolicyId = FinalResult.FINAL_FAILURE_EXCEPTION.toString();
256             throw e;
257         }
258     }
259 }