96f9e5bfe43bfdbf19406d3aae4b75cb90dfaf7d
[policy/drools-pdp.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * policy-management
4  * ================================================================================
5  * Copyright (C) 2017 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.openecomp.policy.drools.system.internal;
22
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Properties;
26
27 import org.openecomp.policy.drools.controller.DroolsController;
28 import org.openecomp.policy.drools.event.comm.Topic;
29 import org.openecomp.policy.drools.event.comm.TopicEndpoint;
30 import org.openecomp.policy.drools.event.comm.TopicListener;
31 import org.openecomp.policy.drools.event.comm.TopicSink;
32 import org.openecomp.policy.drools.event.comm.TopicSource;
33 import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
34 import org.openecomp.policy.common.logging.flexlogger.Logger;
35 import org.openecomp.policy.drools.persistence.SystemPersistence;
36 import org.openecomp.policy.drools.properties.PolicyProperties;
37 import org.openecomp.policy.drools.protocol.configuration.DroolsConfiguration;
38 import org.openecomp.policy.drools.system.PolicyController;
39 import com.fasterxml.jackson.annotation.JsonIgnore;
40
41 /**
42  * This implementation of the Policy Controller merely aggregates and tracks for
43  * management purposes all underlying resources that this controller depends upon.
44  */
45 public class AggregatedPolicyController implements PolicyController, 
46                                                    TopicListener {
47         
48         /**
49          * Logger
50          */
51         private static Logger  logger = FlexLogger.getLogger(AggregatedPolicyController.class); 
52         
53         /**
54          * identifier for this policy controller
55          */
56         protected final String name;
57         
58         /**
59          * Abstracted Event Sources List regardless communication
60          * technology
61          */
62         protected final List<? extends TopicSource> sources;
63         
64         /**
65          * Abstracted Event Sinks List regardless communication
66          * technology
67          */
68         protected final List<? extends TopicSink> sinks;
69         
70         /**
71          * Mapping topics to sinks
72          */
73         @JsonIgnore
74         protected final HashMap<String, TopicSink> topic2Sinks =
75                 new HashMap<String, TopicSink>();
76         
77         /**
78          * Is this Policy Controller running (alive) ?
79          * reflects invocation of start()/stop() only
80          */
81         protected volatile boolean alive;
82         
83         /**
84          * Is this Policy Controller locked ?
85          * reflects if i/o controller related operations and start 
86          * are permitted,
87          * more specifically: start(), deliver() and onTopicEvent().
88          * It does not affect the ability to stop the
89          * underlying drools infrastructure 
90          */
91         protected volatile boolean locked;
92         
93         /**
94          * Policy Drools Controller
95          */
96         protected volatile DroolsController droolsController;
97         
98         /**
99          * Properties used to initialize controller
100          */
101         protected final Properties properties;
102         
103         /**
104          * Constructor version mainly used for bootstrapping at initialization time
105          * a policy engine controller
106          * 
107          * @param name controller name
108          * @param properties
109          * 
110          * @throws IllegalArgumentException when invalid arguments are provided
111          */
112         public AggregatedPolicyController(String name, Properties properties) 
113                         throws IllegalArgumentException {
114                 
115                 this.name = name;
116                 
117                 /*
118                  * 1. Register read topics with network infrastructure (ueb, dmaap, rest)
119                  * 2. Register write topics with network infrastructure (ueb, dmaap, rest)
120                  * 3. Register with drools infrastructure
121                  */
122                 
123                 // Create/Reuse Readers/Writers for all event sources endpoints
124                 
125                 this.sources = TopicEndpoint.manager.addTopicSources(properties);
126                 this.sinks = TopicEndpoint.manager.addTopicSinks(properties);
127                 
128                 initDrools(properties);         
129                 initSinks();            
130                 
131                 /* persist new properties */
132                 SystemPersistence.manager.storeController(name, properties);    
133                 this.properties = properties;
134         }
135         
136         /**
137          * initialize drools layer
138          * @throws IllegalArgumentException if invalid parameters are passed in
139          */
140         protected void initDrools(Properties properties) throws IllegalArgumentException {
141                 try {
142                         // Register with drools infrastructure
143                         this.droolsController = DroolsController.factory.build(properties, sources, sinks);
144                 } catch (Exception | LinkageError e) {
145                         logger.error("BUILD-INIT-DROOLS: " + e.getMessage());
146                         e.printStackTrace();
147                         
148                         // throw back exception as input properties cause problems
149                         throw new IllegalArgumentException(e);
150                 }
151         }
152         
153         /**
154          * initialize sinks
155          * @throws IllegalArgumentException if invalid parameters are passed in
156          */
157         protected void initSinks() throws IllegalArgumentException {
158                 this.topic2Sinks.clear();
159                 for (TopicSink sink: sinks) {
160                         this.topic2Sinks.put(sink.getTopic(), sink);
161                 }
162         }
163         
164         /**
165          * {@inheritDoc}
166          */
167         @Override
168         public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) {
169                 
170                 DroolsConfiguration oldDroolsConfiguration =
171                                 new DroolsConfiguration(this.droolsController.getArtifactId(),
172                                                                                 this.droolsController.getGroupId(), 
173                                                         this.droolsController.getVersion());
174                 
175                 if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId()) &&
176                         oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId()) &&
177                         oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) {
178                         logger.warn("UPDATE-DROOLS: nothing to do: identical configuration: " + oldDroolsConfiguration +
179                                             " <=> " + newDroolsConfiguration);
180                         return true;
181                 }
182                 
183                 try {
184                         /* Drools Controller created, update initialization properties for restarts */
185                         
186                         this.properties.setProperty(PolicyProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId());
187                         this.properties.setProperty(PolicyProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId());
188                         this.properties.setProperty(PolicyProperties.RULES_VERSION, newDroolsConfiguration.getVersion());
189                                         
190                         SystemPersistence.manager.storeController(name, this.properties);
191                         
192                         this.initDrools(this.properties);
193                         
194                         /* set drools controller to current locked status */
195                         
196                         if (this.isLocked())
197                                 this.droolsController.lock();
198                         else
199                                 this.droolsController.unlock();
200                         
201                         /* set drools controller to current alive status */
202                         
203                         if (this.isAlive())
204                                 this.droolsController.start();
205                         else
206                                 this.droolsController.stop();
207                         
208                 } catch (IllegalArgumentException e) {
209                         logger.warn("INIT-DROOLS: " + e.getMessage());
210                         e.printStackTrace();
211                         return false;
212                 }       
213                 
214                 return true;
215         }
216
217         /**
218          * {@inheritDoc}
219          */
220         @Override
221         public String getName() {
222                 return this.name;
223         }
224
225         /**
226          * {@inheritDoc}
227          */
228         @Override
229         public boolean start() throws IllegalStateException {
230                 if (logger.isInfoEnabled())
231                         logger.info("START: " + this);
232                 
233                 if (this.isLocked())
234                         throw new IllegalStateException("Policy Controller " + name  + " is locked");
235
236                 synchronized(this) {
237                         if (this.alive)
238                                 return true;
239                         
240                         this.alive = true;
241                 }
242
243                 boolean success = this.droolsController.start();
244                 
245                 // register for events
246                 
247                 for (TopicSource source: sources) {
248                         source.register(this);
249                 }
250                 
251                 for (TopicSink sink: sinks) {
252                         try {
253                                 sink.start();
254                         } catch (Exception e) {
255                                 logger.warn("can't start sink: " + sink + " because of " + e.getMessage());
256                                 e.printStackTrace();
257                         }
258                 }
259                 
260                 return success;
261         }
262
263         /**
264          * {@inheritDoc}
265          */
266         @Override
267         public boolean stop() {
268                 
269                 logger.info("STOP: " + this);
270                 
271                 /* stop regardless locked state */
272                 
273                 synchronized(this) {
274                         if (!this.alive)
275                                 return true;
276                         
277                         this.alive = false;
278                 }
279                 
280                 // 1. Stop registration
281                 
282                 for (TopicSource source: sources) {
283                         source.unregister(this);
284                 }
285                 
286                 boolean success = this.droolsController.stop();
287                 return success;
288         }
289         
290         /**
291          * {@inheritDoc}
292          */
293         @Override
294         public void shutdown() throws IllegalStateException {
295                 if (logger.isInfoEnabled())
296                         logger.info(this  + "SHUTDOWN");
297                 
298                 this.stop();
299                 
300                 DroolsController.factory.shutdown(this.droolsController);
301         }
302         
303         /**
304          * {@inheritDoc}
305          */
306         @Override
307         public void halt() throws IllegalStateException {
308                 if (logger.isInfoEnabled())
309                         logger.info(this + "HALT");
310                 
311                 this.stop();    
312                 DroolsController.factory.destroy(this.droolsController);
313                 SystemPersistence.manager.deleteController(this.name);
314         }
315         
316         /**
317          * {@inheritDoc}
318          */
319         @Override
320         public boolean onTopicEvent(Topic.CommInfrastructure commType, 
321                                             String topic, String event) {
322
323                 logger.info("EVENT NOTIFICATION: " + commType + ":" + topic + ":" + event +  " INTO " + this);
324                 
325                 if (this.locked)
326                         return false;
327                 
328                 if (!this.alive)
329                         return true;
330                 
331                 return this.droolsController.offer(topic, event);
332         }
333         
334         /**
335          * {@inheritDoc}
336          */
337         @Override
338         public boolean deliver(Topic.CommInfrastructure commType, 
339                                        String topic, Object event)
340                 throws IllegalArgumentException, IllegalStateException,
341                UnsupportedOperationException {  
342                 
343                 logger.info("DELIVER: " + commType + ":" + topic + ":" + event +  " FROM " + this);
344                 
345                 if (topic == null || topic.isEmpty())
346                         throw new IllegalArgumentException("Invalid Topic");
347                 
348                 if (event == null)
349                         throw new IllegalArgumentException("Invalid Event");
350                 
351                 if (!this.isAlive())
352                         throw new IllegalStateException("Policy Engine is stopped");
353                 
354                 if (this.isLocked())
355                         throw new IllegalStateException("Policy Engine is locked");
356                 
357                 if (!this.topic2Sinks.containsKey(topic)) {
358                         logger.error("UNDELIVERED: " + commType + ":" + topic + ":" + event +  " FROM " + this);
359                         throw new IllegalArgumentException
360                                         ("Unsuported topic " + topic + " for delivery");
361                 }
362                 
363                 return this.droolsController.deliver
364                                 (this.topic2Sinks.get(topic), event);
365         }
366
367         /**
368          * {@inheritDoc}
369          */
370         @Override
371         public boolean isAlive() {
372                 return this.alive;
373         }
374
375         /**
376          * {@inheritDoc}
377          */
378         @Override
379         public boolean lock() {
380                 logger.info("LOCK: " + this);
381                 
382                 synchronized(this) {
383                         if (this.locked)
384                                 return true;
385                         
386                         this.locked = true;
387                 }
388                 
389                 // it does not affect associated sources/sinks, they are
390                 // autonomous entities
391                 
392                 return this.droolsController.lock();
393         }
394
395         /**
396          * {@inheritDoc}
397          */
398         @Override
399         public boolean unlock() {
400                 logger.info("UNLOCK: " + this);
401                 
402                 synchronized(this) {
403                         if (!this.locked)
404                                 return true;
405                         
406                         this.locked = false;
407                 }
408                 
409                 return this.droolsController.unlock();
410         }
411
412         /**
413          * {@inheritDoc}
414          */
415         @Override
416         public boolean isLocked() {
417                 return this.locked;
418         }
419
420         /**
421          * {@inheritDoc}
422          */
423         @Override
424         public List<? extends TopicSource> getTopicSources() {
425                 return this.sources;
426         }
427
428         /**
429          * {@inheritDoc}
430          */
431         @Override
432         public List<? extends TopicSink> getTopicSinks() {
433                 return this.sinks;
434         }
435
436         /**
437          * {@inheritDoc}
438          */
439         @Override
440         public DroolsController getDrools() {
441                 return this.droolsController;
442         }
443
444         @Override
445         public String toString() {
446                 StringBuilder builder = new StringBuilder();
447                 builder.append("AggregatedPolicyController [name=").append(name).append(", sources=").append(sources)
448                                 .append(", sinks=").append(sinks).append(", alive=").append(alive).append(", locked=").append(locked)
449                                 .append(", droolsController=").append(droolsController).append("]");
450                 return builder.toString();
451         }
452
453         /**
454          * {@inheritDoc}
455          */
456         @Override
457         public Properties getInitializationProperties() {
458                 return this.properties;
459         }
460
461 }
462