Resolve bug in DroolsPDPIntegrityMonitor
[policy/drools-pdp.git] / feature-state-management / src / main / java / org / onap / policy / drools / statemanagement / DroolsPDPIntegrityMonitor.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * feature-state-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.onap.policy.drools.statemanagement;
22
23 import java.util.ArrayList;
24 import java.util.Properties;
25 import org.onap.policy.common.im.IntegrityMonitor;
26 import org.onap.policy.common.im.IntegrityMonitorException;
27 import org.onap.policy.drools.http.server.HttpServletServer;
28 import org.onap.policy.drools.properties.Startable;
29 import org.onap.policy.drools.utils.PropertyUtil;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 /**
34  * This class extends 'IntegrityMonitor' for use in the 'Drools PDP'
35  * virtual machine. The included audits are 'Database' and 'Repository'.
36  */
37 public class DroolsPDPIntegrityMonitor extends IntegrityMonitor
38 {
39         
40         private static final String INVALID_PROPERTY_VALUE = "init: property {} does not have the expected value of {}";
41
42 // get an instance of logger 
43   private static final Logger  logger = LoggerFactory.getLogger(DroolsPDPIntegrityMonitor.class);       
44
45   // static global instance
46   private static DroolsPDPIntegrityMonitor im = null;
47
48   // list of audits to run
49   private static AuditBase[] audits =
50         new AuditBase[]{DbAudit.getInstance(), RepositoryAudit.getInstance()};
51   
52   private static Properties subsystemTestProperties = null;
53
54   private static final String PROPERTIES_NAME = "feature-state-management.properties";
55
56   /**
57    * Constructor - pass arguments to superclass, but remember properties
58    * @param resourceName unique name of this Integrity Monitor
59    * @param url the JMX URL of the MBean server
60    * @param properties properties used locally, as well as by
61    *    'IntegrityMonitor'
62    * @throws Exception (passed from superclass)
63    */
64         private DroolsPDPIntegrityMonitor(String resourceName,
65                         Properties consolidatedProperties
66                         ) throws Exception {
67         super(resourceName, consolidatedProperties);
68   }
69   
70   private static void missingProperty(String prop) throws StateManagementPropertiesException{
71                 String msg = "init: missing IntegrityMonitor property: ".concat(prop);
72                 logger.error(msg);
73                 throw new StateManagementPropertiesException(msg);
74   }
75   
76   private static void logPropertyValue(String prop, String val){
77           if(logger.isInfoEnabled()){
78                   String msg = "\n\n    init: property: " + prop + " = " + val + "\n";
79                   logger.info(msg);
80           }
81   }
82   
83   /**
84    * Static initialization -- create Drools Integrity Monitor, and
85    * an HTTP server to handle REST 'test' requests
86    */
87   public static DroolsPDPIntegrityMonitor init(String configDir) throws Exception
88   {
89                   
90         logger.info("init: Entering and invoking PropertyUtil.getProperties() on '{}'", configDir);
91                 
92         // read in properties
93         Properties stateManagementProperties =
94           PropertyUtil.getProperties(configDir + "/" + PROPERTIES_NAME);
95         // fetch and verify definitions of some properties
96         // (the 'IntegrityMonitor' constructor does some additional verification)
97         String testHost = stateManagementProperties.getProperty(StateManagementProperties.TEST_HOST);
98         String testPort = stateManagementProperties.getProperty(StateManagementProperties.TEST_PORT);
99     String testServices = stateManagementProperties.getProperty(StateManagementProperties.TEST_SERVICES);
100     String testRestClasses = stateManagementProperties.getProperty(StateManagementProperties.TEST_REST_CLASSES);
101     String testManaged = stateManagementProperties.getProperty(StateManagementProperties.TEST_MANAGED);
102     String testSwagger = stateManagementProperties.getProperty(StateManagementProperties.TEST_SWAGGER);
103         String resourceName = stateManagementProperties.getProperty(StateManagementProperties.RESOURCE_NAME);
104         String fpMonitorInterval = stateManagementProperties.getProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
105         String failedCounterThreshold = stateManagementProperties.getProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
106         String testTransInterval = stateManagementProperties.getProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
107         String writeFpcInterval = stateManagementProperties.getProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
108         String siteName = stateManagementProperties.getProperty(StateManagementProperties.SITE_NAME);
109         String nodeType = stateManagementProperties.getProperty(StateManagementProperties.NODE_TYPE);
110         String dependencyGroups = stateManagementProperties.getProperty(StateManagementProperties.DEPENDENCY_GROUPS);
111         String javaxPersistenceJdbcDriver = stateManagementProperties.getProperty(StateManagementProperties.DB_DRIVER);
112         String javaxPersistenceJdbcUrl = stateManagementProperties.getProperty(StateManagementProperties.DB_URL);
113         String javaxPersistenceJdbcUser = stateManagementProperties.getProperty(StateManagementProperties.DB_USER);
114         String javaxPersistenceJdbcPassword = stateManagementProperties.getProperty(StateManagementProperties.DB_PWD);
115
116         if (testHost == null){
117                 missingProperty(StateManagementProperties.TEST_HOST);
118         }
119         if (testPort == null){
120                 missingProperty(StateManagementProperties.TEST_PORT);
121         }
122     if (testServices == null) {
123         testServices = StateManagementProperties.TEST_SERVICES_DEFAULT;
124         stateManagementProperties.put(StateManagementProperties.TEST_SERVICES, testServices);
125     }
126     if (testRestClasses == null) {
127         testRestClasses = StateManagementProperties.TEST_REST_CLASSES_DEFAULT;
128         stateManagementProperties.put(StateManagementProperties.TEST_REST_CLASSES, testRestClasses);
129     }
130     if (testManaged == null) {
131         testManaged = StateManagementProperties.TEST_MANAGED_DEFAULT;
132         stateManagementProperties.put(StateManagementProperties.TEST_MANAGED, testManaged);
133     }
134     if (testSwagger == null) {
135         testSwagger = StateManagementProperties.TEST_SWAGGER_DEFAULT;
136         stateManagementProperties.put(StateManagementProperties.TEST_SWAGGER, testSwagger);
137     }
138         if (!testServices.equals(StateManagementProperties.TEST_SERVICES_DEFAULT)){
139                 logger.error(INVALID_PROPERTY_VALUE,
140                                 StateManagementProperties.TEST_SERVICES,
141                                 StateManagementProperties.TEST_SERVICES_DEFAULT);
142         }
143         if (!testRestClasses.equals(StateManagementProperties.TEST_REST_CLASSES_DEFAULT)){
144                 logger.error(INVALID_PROPERTY_VALUE,
145                                 StateManagementProperties.TEST_REST_CLASSES,
146                                 StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
147         }
148         if (!testManaged.equals(StateManagementProperties.TEST_MANAGED_DEFAULT)){
149                 logger.warn(INVALID_PROPERTY_VALUE,
150                                 StateManagementProperties.TEST_MANAGED,
151                                 StateManagementProperties.TEST_MANAGED_DEFAULT);
152         }
153         if (!testSwagger.equals(StateManagementProperties.TEST_SWAGGER_DEFAULT)){
154                 logger.warn(INVALID_PROPERTY_VALUE,
155                                 StateManagementProperties.TEST_SWAGGER,
156                                 StateManagementProperties.TEST_SWAGGER_DEFAULT);
157         }
158         if (resourceName == null){
159                 missingProperty(StateManagementProperties.RESOURCE_NAME);
160           }
161         if (fpMonitorInterval == null){
162                 missingProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
163           }     
164         if (failedCounterThreshold == null){
165                 missingProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
166           }     
167         if (testTransInterval == null){
168                 missingProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
169           }     
170         if (writeFpcInterval == null){
171                 missingProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
172           }     
173         if (siteName == null){
174                 missingProperty(StateManagementProperties.SITE_NAME);
175           }     
176         if (nodeType == null){
177                 missingProperty(StateManagementProperties.NODE_TYPE);
178           }     
179         if (dependencyGroups == null){
180                 missingProperty(StateManagementProperties.DEPENDENCY_GROUPS);
181           }     
182         if (javaxPersistenceJdbcDriver == null){
183                 missingProperty(StateManagementProperties.DB_DRIVER);
184           }             
185         if (javaxPersistenceJdbcUrl == null){
186                 missingProperty(StateManagementProperties.DB_URL);
187           }                     
188         if (javaxPersistenceJdbcUser == null){
189                 missingProperty(StateManagementProperties.DB_USER);
190           }                     
191         if (javaxPersistenceJdbcPassword == null){
192                 missingProperty(StateManagementProperties.DB_PWD);
193           }
194         
195         //Log the values so we can diagnose any issues
196         logPropertyValue(StateManagementProperties.TEST_HOST,testHost);
197         logPropertyValue(StateManagementProperties.TEST_PORT,testPort);
198         logPropertyValue(StateManagementProperties.TEST_SERVICES,testServices);
199         logPropertyValue(StateManagementProperties.TEST_REST_CLASSES,testRestClasses);
200         logPropertyValue(StateManagementProperties.TEST_MANAGED,testManaged);
201         logPropertyValue(StateManagementProperties.TEST_SWAGGER,testSwagger);
202         logPropertyValue(StateManagementProperties.RESOURCE_NAME,resourceName);
203         logPropertyValue(StateManagementProperties.FP_MONITOR_INTERVAL,fpMonitorInterval);
204         logPropertyValue(StateManagementProperties.FAILED_COUNTER_THRESHOLD,failedCounterThreshold);
205         logPropertyValue(StateManagementProperties.TEST_TRANS_INTERVAL,testTransInterval);
206         logPropertyValue(StateManagementProperties.WRITE_FPC_INTERVAL,writeFpcInterval);
207         logPropertyValue(StateManagementProperties.SITE_NAME,siteName);
208         logPropertyValue(StateManagementProperties.NODE_TYPE,nodeType);
209         logPropertyValue(StateManagementProperties.DEPENDENCY_GROUPS,dependencyGroups);
210         logPropertyValue(StateManagementProperties.DB_DRIVER,javaxPersistenceJdbcDriver);
211         logPropertyValue(StateManagementProperties.DB_URL,javaxPersistenceJdbcUrl);
212         logPropertyValue(StateManagementProperties.DB_USER,javaxPersistenceJdbcUser);
213         logPropertyValue(StateManagementProperties.DB_PWD,javaxPersistenceJdbcPassword);
214                 
215         subsystemTestProperties = stateManagementProperties;
216
217         // Now that we've validated the properties, create Drools Integrity Monitor
218         // with these properties.
219         im = new DroolsPDPIntegrityMonitor(resourceName,
220                                 stateManagementProperties);
221         logger.info("init: New DroolsPDPIntegrityMonitor instantiated, resourceName = ", resourceName);
222
223         // create http server
224         try {
225                 logger.info("init: Starting HTTP server, addr= {}", testHost+":"+testPort);
226                 IntegrityMonitorRestServer server = new IntegrityMonitorRestServer();
227                 
228                 server.init(stateManagementProperties);
229         } catch (Exception e) {
230                 logger.error("init: Caught Exception attempting to start server on testPort= {} message:",
231                                                                 testPort, e);
232                 throw e;
233         }
234         logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor");
235         return im;
236   }
237
238   /**
239    * Run tests (audits) unique to Drools PDP VM (Database + Repository)
240    */
241   @Override
242         public void subsystemTest() throws IntegrityMonitorException
243   {
244         logger.info("DroolsPDPIntegrityMonitor.subsystemTest called");
245
246         // clear all responses (non-null values indicate an error)
247         for (AuditBase audit : audits)
248           {
249                 audit.setResponse(null);
250           }
251
252         // invoke all of the audits
253         for (AuditBase audit : audits)
254           {
255                 try
256                   {
257                         // invoke the audit (responses are stored within the audit object)
258                         audit.invoke(subsystemTestProperties);
259                   }
260                 catch (Exception e)
261                   {
262                         logger.error("{} audit error", audit.getName(), e);
263                         if (audit.getResponse() == null)
264                           {
265                                 // if there is no current response, use the exception message
266                                 audit.setResponse(e.getMessage());
267                           }
268                   }
269           }
270         
271           // will contain list of subsystems where the audit failed
272           String responseMsg = "";
273
274           // Loop through all of the audits, and see which ones have failed.
275           // NOTE: response information is stored within the audit objects
276           // themselves -- only one can run at a time.
277           for (AuditBase audit : audits)
278                 {
279                   String response = audit.getResponse();
280                   if (response != null)
281                         {
282                           // the audit has failed -- add subsystem and 
283                           // and 'responseValue' with the new information
284                           responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response);
285                         }
286                 }
287           
288           if(!responseMsg.isEmpty()){
289                   throw new IntegrityMonitorException(responseMsg);
290           }
291   }
292
293   /* ============================================================ */
294
295   /**
296    * This is the base class for audits invoked in 'subsystemTest'
297    */
298   public abstract static class AuditBase
299   {
300         // name of the audit
301         protected String name;
302
303         // non-null indicates the error response
304         protected String response;
305
306         /**
307          * Constructor - initialize the name, and clear the initial response
308          * @param name name of the audit
309          */
310         public AuditBase(String name)
311         {
312           this.name = name;
313           this.response = null;
314         }
315
316         /**
317          * @return the name of this audit
318          */
319         public String getName()
320         {
321           return name;
322         }
323
324         /**
325          * @return the response String (non-null indicates the error message)
326          */
327         public String getResponse()
328         {
329           return response;
330         }
331
332         /**
333          * Set the response string to the specified value
334          * @param value the new value of the response string (null = no errors)
335          */
336         public void setResponse(String value)
337         {
338           response = value;
339         }
340
341         /**
342          * Abstract method to invoke the audit
343          * @param persistenceProperties Used for DB access
344          * @throws Exception passed in by the audit
345          */
346         abstract void invoke(Properties persistenceProperties) throws Exception;
347   }
348   
349         public static class IntegrityMonitorRestServer implements Startable {
350                 protected volatile HttpServletServer server = null;
351                 protected volatile Properties integrityMonitorRestServerProperties = null;
352                 
353                 public void init(Properties props) {
354                         this.integrityMonitorRestServerProperties = props;
355                         this.start();
356                 }
357                 
358                 @Override
359                 public boolean start() {
360                         try {
361                                 ArrayList<HttpServletServer> servers = HttpServletServer.factory.build(integrityMonitorRestServerProperties);
362                                 
363                                 if (!servers.isEmpty()) {
364                                         server = servers.get(0);
365                                         
366                                         waitServerStart();
367                                 }
368                         } catch (Exception e) {
369                                 logger.error("Exception building servers", e);
370                                 return false;
371                         }
372                         
373                         return true;
374                 }
375
376                 private void waitServerStart() {
377                         try {
378                                 server.waitedStart(5);
379                         } catch (Exception e) {
380                                 logger.error("Exception waiting for servers to start: ", e);
381                         }
382                 }
383
384                 @Override
385                 public boolean stop() {
386                         try {
387                                 server.stop();
388                         } catch (Exception e) {
389                                 logger.error("Exception during stop", e);
390                         }
391                         
392                         return true;
393                 }
394
395                 @Override
396                 public void shutdown() {
397                         this.stop();
398                 }
399                 
400                 @Override
401                 public synchronized boolean isAlive() {
402                         return this.integrityMonitorRestServerProperties != null;
403                 }
404         }
405
406         public static DroolsPDPIntegrityMonitor getInstance() throws Exception{
407                 if(logger.isDebugEnabled()){
408                         logger.debug("getInstance() called");
409                 }
410                 if (im == null) {
411                         String msg = "No DroolsPDPIntegrityMonitor instance exists."
412                                         + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)";
413                         throw new Exception(msg);
414                 }else{
415                         return im;
416                 }
417         }
418 }