9a11955a21d8e5acaacf3a21af53fcc1ae1e6cc6
[policy/drools-pdp.git] /
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 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.drools.lifecycle;
22
23 import com.fasterxml.jackson.annotation.JsonIgnore;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Properties;
28 import java.util.stream.Collectors;
29 import lombok.Getter;
30 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
31 import org.onap.policy.common.endpoints.event.comm.TopicSink;
32 import org.onap.policy.common.endpoints.event.comm.TopicSource;
33 import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
34 import org.onap.policy.common.utils.coder.CoderException;
35 import org.onap.policy.drools.domain.models.controller.ControllerCustomSerialization;
36 import org.onap.policy.drools.domain.models.controller.ControllerEvent;
37 import org.onap.policy.drools.domain.models.controller.ControllerPolicy;
38 import org.onap.policy.drools.domain.models.controller.ControllerProperties;
39 import org.onap.policy.drools.domain.models.controller.ControllerSinkTopic;
40 import org.onap.policy.drools.domain.models.controller.ControllerSourceTopic;
41 import org.onap.policy.drools.properties.DroolsPropertyConstants;
42 import org.onap.policy.drools.system.PolicyController;
43 import org.onap.policy.drools.system.PolicyControllerConstants;
44 import org.onap.policy.drools.system.PolicyEngineConstants;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
46 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class PolicyTypeNativeDroolsController implements PolicyTypeController {
51     private static final Logger logger = LoggerFactory.getLogger(PolicyTypeNativeDroolsController.class);
52
53     @Getter
54     protected final ToscaPolicyTypeIdentifier policyType;
55
56     @GsonJsonIgnore
57     @JsonIgnore
58     protected final LifecycleFsm fsm;
59
60     public PolicyTypeNativeDroolsController(LifecycleFsm fsm, ToscaPolicyTypeIdentifier policyType) {
61         this.policyType = policyType;
62         this.fsm = fsm;
63     }
64
65     @Override
66     public boolean deploy(ToscaPolicy policy) {
67         Properties controllerProps = new Properties();
68         ControllerPolicy controllerPolicy = toDomainPolicy(policy);
69         if (controllerPolicy == null) {
70             return false;
71         }
72
73         ControllerProperties controllerConfig = controllerPolicy.getProperties();
74
75         configControllerName(controllerConfig, controllerProps);
76
77         boolean success =
78             configControllerSources(controllerConfig, controllerProps)
79             && configControllerSinks(controllerConfig, controllerProps)
80             && configControllerCustom(controllerConfig, controllerProps);
81
82         if (!success) {
83             return false;
84         }
85
86         PolicyController controller;
87         try {
88             controller =
89                 PolicyEngineConstants.getManager()
90                     .createPolicyController(controllerConfig.getControllerName(), controllerProps);
91         } catch (RuntimeException e) {
92             logger.warn("failed deploy (cannot create controller) for policy: {}", policy, e);
93             return false;
94         }
95
96         try {
97             controller.start();
98         } catch (RuntimeException e) {
99             logger.warn("failed deploy (cannot start ontroller) for policy: {}", policy, e);
100             PolicyEngineConstants.getManager().removePolicyController(controller);
101             return false;
102         }
103
104         return true;
105     }
106
107     @Override
108     public boolean undeploy(ToscaPolicy policy) {
109         try {
110             ControllerPolicy nativePolicy = fsm.getDomainMaker().convertTo(policy, ControllerPolicy.class);
111             PolicyEngineConstants.getManager()
112                     .removePolicyController(nativePolicy.getProperties().getControllerName());
113             return true;
114         } catch (RuntimeException | CoderException e) {
115             logger.warn("failed undeploy of policy: {}", policy);
116             return false;
117         }
118     }
119
120     private ControllerPolicy toDomainPolicy(ToscaPolicy policy) {
121         ControllerPolicy nativePolicy = null;
122         try {
123             nativePolicy = fsm.getDomainMaker().convertTo(policy, ControllerPolicy.class);
124             ControllerProperties config = nativePolicy.getProperties();
125
126             /* check for duplicates */
127
128             if (isDups(sourceTopics(config.getSourceTopics()))
129                         || isDups(sinkTopics(config.getSinkTopics()))) {
130                 logger.warn("there are duplicated topics in policy {}", policy);
131                 return null;
132             }
133
134             /* check for non-existance of the controller - throws IAE if there's not */
135
136             PolicyControllerConstants.getFactory().get(nativePolicy.getProperties().getControllerName());
137
138         } catch (CoderException e) {
139             logger.warn("failed deploy of policy (invalid): {}", policy);
140             return null;
141         } catch (IllegalArgumentException e) {
142             // this is OK
143             logger.trace("proceeding with the deploy of native controller policy: {}", policy);
144         }
145
146         return nativePolicy;
147     }
148
149     private void configControllerName(ControllerProperties controllerConfig, Properties controllerProps)  {
150         controllerProps
151                 .setProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_NAME, controllerConfig.getControllerName());
152     }
153
154     private boolean configControllerSources(ControllerProperties controllerConfig, Properties controllerProps) {
155         if (controllerConfig.getSourceTopics() == null) {
156             return true;
157         }
158
159         for (ControllerSourceTopic configSourceTopic : controllerConfig.getSourceTopics()) {
160             List<TopicSource> sources =
161                     TopicEndpointManager.getManager().getTopicSources(List.of(configSourceTopic.getTopicName()));
162             if (sources.size() != 1) {
163                 logger.warn("Topic {} is not present or ambigous {}", configSourceTopic.getTopicName(), sources);
164                 return false;
165             }
166
167             configSourceTopic(sources.get(0), configSourceTopic, controllerProps);
168         }
169         return true;
170     }
171
172     private void configSourceTopic(TopicSource topic, ControllerSourceTopic configTopic, Properties controllerProps) {
173         String configCommPrefix = topic.getTopicCommInfrastructure().name().toLowerCase() + ".source";
174         configTopic(configCommPrefix, topic.getTopic(), configTopic.getEvents(), controllerProps);
175     }
176
177     private boolean configControllerSinks(ControllerProperties controllerConfig, Properties controllerProps) {
178         if (controllerConfig.getSinkTopics() == null) {
179             return true;
180         }
181
182         for (ControllerSinkTopic configSinkTopic : controllerConfig.getSinkTopics()) {
183             List<TopicSink> sinks =
184                     TopicEndpointManager.getManager().getTopicSinks(List.of(configSinkTopic.getTopicName()));
185             if (sinks.size() != 1) {
186                 logger.warn("Topic {} is not present or ambigous {}", configSinkTopic.getTopicName(), sinks);
187                 return false;
188             }
189
190             configSinkTopic(sinks.get(0), configSinkTopic, controllerProps);
191         }
192         return true;
193     }
194
195     private void configSinkTopic(TopicSink topic, ControllerSinkTopic configTopic, Properties controllerProps) {
196         String configCommPrefix = topic.getTopicCommInfrastructure().name().toLowerCase() + ".sink";
197         configTopic(configCommPrefix, topic.getTopic(), configTopic.getEvents(), controllerProps);
198     }
199
200     private void configTopic(
201             String configCommPrefix, String topicName, List<ControllerEvent> events, Properties controllerProps) {
202         String configTopicPrefix = configCommPrefix + "." + topicName;
203         configTopics(configCommPrefix, topicName, controllerProps);
204         for (ControllerEvent configEvent : events) {
205             configEvent(configTopicPrefix, configEvent, controllerProps);
206         }
207     }
208
209     private void configTopics(String propPrefix, String topicName, Properties controllerProps) {
210         String topicsPropKey = propPrefix + ".topics";
211         configTopicItemList(topicsPropKey, topicName, controllerProps);
212     }
213
214     private void configEvent(String propPrefix, ControllerEvent configEvent, Properties controllerProps) {
215         String eventPropPrefix = propPrefix + ".events";
216         controllerProps.setProperty(eventPropPrefix, configEvent.getEventClass());
217         if (configEvent.getEventFilter() != null) {
218             controllerProps.setProperty(
219                 eventPropPrefix + "." + configEvent.getEventClass() + ".filter", configEvent.getEventFilter());
220         }
221         if (configEvent.getCustomSerialization() != null) {
222             configSerialization(eventPropPrefix, configEvent.getCustomSerialization(), controllerProps);
223         }
224         configTopicItemList(eventPropPrefix, configEvent.getEventClass(), controllerProps);
225     }
226
227     private void configTopicItemList(String itemPrefix, String item, Properties controllerProps) {
228         if (controllerProps.getProperty(itemPrefix) == null) {
229             controllerProps.setProperty(itemPrefix, item);
230         } else {
231             controllerProps.setProperty(itemPrefix, "," + item);
232         }
233     }
234
235     private void configSerialization(
236             String propPrefix, ControllerCustomSerialization configCustom, Properties controllerProps) {
237         String customPropPrefix = propPrefix + ".custom.gson";
238         controllerProps.setProperty(
239                 customPropPrefix, configCustom.getCustomSerializerClass() + "," + configCustom.getJsonParser());
240     }
241
242     private boolean configControllerCustom(ControllerProperties controllerConfig, Properties controllerProps) {
243         Map<String, String> configCustom = controllerConfig.getCustomConfig();
244         if (configCustom != null && !configCustom.isEmpty()) {
245             controllerProps.putAll(configCustom);
246         }
247
248         return true;
249     }
250
251     private <T> boolean isDups(List<T> items) {
252         return items.size() != items.stream().distinct().count();
253     }
254
255     private List<String> sourceTopics(List<ControllerSourceTopic> sourceTopics) {
256         if (sourceTopics == null) {
257             return Collections.emptyList();
258         }
259
260         return sourceTopics.stream()
261                        .map(ControllerSourceTopic::getTopicName)
262                        .collect(Collectors.toList());
263     }
264
265     private List<String> sinkTopics(List<ControllerSinkTopic> sinkTopics) {
266         if (sinkTopics == null) {
267             return Collections.emptyList();
268         }
269
270         return sinkTopics.stream()
271                        .map(ControllerSinkTopic::getTopicName)
272                        .collect(Collectors.toList());
273     }
274
275 }