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