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