688631bb70c1f116628282c4f0d8c64a9f24d1ff
[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                         StateManagementProperties.TEST_SERVICES_DEFAULT);
101         String testRestClasses = stateManagementProperties.getProperty(StateManagementProperties.TEST_REST_CLASSES, 
102                         StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
103         String testManaged = stateManagementProperties.getProperty(StateManagementProperties.TEST_MANAGED,
104                         StateManagementProperties.TEST_MANAGED_DEFAULT);
105         String testSwagger = stateManagementProperties.getProperty(StateManagementProperties.TEST_SWAGGER,
106                         StateManagementProperties.TEST_SWAGGER_DEFAULT);
107         String resourceName = stateManagementProperties.getProperty(StateManagementProperties.RESOURCE_NAME);
108         String fpMonitorInterval = stateManagementProperties.getProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
109         String failedCounterThreshold = stateManagementProperties.getProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
110         String testTransInterval = stateManagementProperties.getProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
111         String writeFpcInterval = stateManagementProperties.getProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
112         String siteName = stateManagementProperties.getProperty(StateManagementProperties.SITE_NAME);
113         String nodeType = stateManagementProperties.getProperty(StateManagementProperties.NODE_TYPE);
114         String dependencyGroups = stateManagementProperties.getProperty(StateManagementProperties.DEPENDENCY_GROUPS);
115         String javaxPersistenceJdbcDriver = stateManagementProperties.getProperty(StateManagementProperties.DB_DRIVER);
116         String javaxPersistenceJdbcUrl = stateManagementProperties.getProperty(StateManagementProperties.DB_URL);
117         String javaxPersistenceJdbcUser = stateManagementProperties.getProperty(StateManagementProperties.DB_USER);
118         String javaxPersistenceJdbcPassword = stateManagementProperties.getProperty(StateManagementProperties.DB_PWD);
119
120         if (testHost == null){
121                 missingProperty(StateManagementProperties.TEST_HOST);
122         }
123         if (testPort == null){
124                 missingProperty(StateManagementProperties.TEST_PORT);
125         }
126         if (!testServices.equals(StateManagementProperties.TEST_SERVICES_DEFAULT)){
127                 logger.error(INVALID_PROPERTY_VALUE,
128                                 StateManagementProperties.TEST_SERVICES,
129                                 StateManagementProperties.TEST_SERVICES_DEFAULT);
130         }
131         if (!testRestClasses.equals(StateManagementProperties.TEST_REST_CLASSES_DEFAULT)){
132                 logger.error(INVALID_PROPERTY_VALUE,
133                                 StateManagementProperties.TEST_REST_CLASSES,
134                                 StateManagementProperties.TEST_REST_CLASSES_DEFAULT);
135         }
136         if (!testManaged.equals(StateManagementProperties.TEST_MANAGED_DEFAULT)){
137                 logger.warn(INVALID_PROPERTY_VALUE,
138                                 StateManagementProperties.TEST_MANAGED,
139                                 StateManagementProperties.TEST_MANAGED_DEFAULT);
140         }
141         if (!testSwagger.equals(StateManagementProperties.TEST_SWAGGER_DEFAULT)){
142                 logger.warn(INVALID_PROPERTY_VALUE,
143                                 StateManagementProperties.TEST_SWAGGER,
144                                 StateManagementProperties.TEST_SWAGGER_DEFAULT);
145         }
146         if (resourceName == null){
147                 missingProperty(StateManagementProperties.RESOURCE_NAME);
148           }
149         if (fpMonitorInterval == null){
150                 missingProperty(StateManagementProperties.FP_MONITOR_INTERVAL);
151           }     
152         if (failedCounterThreshold == null){
153                 missingProperty(StateManagementProperties.FAILED_COUNTER_THRESHOLD);
154           }     
155         if (testTransInterval == null){
156                 missingProperty(StateManagementProperties.TEST_TRANS_INTERVAL);
157           }     
158         if (writeFpcInterval == null){
159                 missingProperty(StateManagementProperties.WRITE_FPC_INTERVAL);
160           }     
161         if (siteName == null){
162                 missingProperty(StateManagementProperties.SITE_NAME);
163           }     
164         if (nodeType == null){
165                 missingProperty(StateManagementProperties.NODE_TYPE);
166           }     
167         if (dependencyGroups == null){
168                 missingProperty(StateManagementProperties.DEPENDENCY_GROUPS);
169           }     
170         if (javaxPersistenceJdbcDriver == null){
171                 missingProperty(StateManagementProperties.DB_DRIVER);
172           }             
173         if (javaxPersistenceJdbcUrl == null){
174                 missingProperty(StateManagementProperties.DB_URL);
175           }                     
176         if (javaxPersistenceJdbcUser == null){
177                 missingProperty(StateManagementProperties.DB_USER);
178           }                     
179         if (javaxPersistenceJdbcPassword == null){
180                 missingProperty(StateManagementProperties.DB_PWD);
181           }
182         
183         //Log the values so we can diagnose any issues
184         logPropertyValue(StateManagementProperties.TEST_HOST,testHost);
185         logPropertyValue(StateManagementProperties.TEST_PORT,testPort);
186         logPropertyValue(StateManagementProperties.TEST_SERVICES,testServices);
187         logPropertyValue(StateManagementProperties.TEST_REST_CLASSES,testRestClasses);
188         logPropertyValue(StateManagementProperties.TEST_MANAGED,testManaged);
189         logPropertyValue(StateManagementProperties.TEST_SWAGGER,testSwagger);
190         logPropertyValue(StateManagementProperties.RESOURCE_NAME,resourceName);
191         logPropertyValue(StateManagementProperties.FP_MONITOR_INTERVAL,fpMonitorInterval);
192         logPropertyValue(StateManagementProperties.FAILED_COUNTER_THRESHOLD,failedCounterThreshold);
193         logPropertyValue(StateManagementProperties.TEST_TRANS_INTERVAL,testTransInterval);
194         logPropertyValue(StateManagementProperties.WRITE_FPC_INTERVAL,writeFpcInterval);
195         logPropertyValue(StateManagementProperties.SITE_NAME,siteName);
196         logPropertyValue(StateManagementProperties.NODE_TYPE,nodeType);
197         logPropertyValue(StateManagementProperties.DEPENDENCY_GROUPS,dependencyGroups);
198         logPropertyValue(StateManagementProperties.DB_DRIVER,javaxPersistenceJdbcDriver);
199         logPropertyValue(StateManagementProperties.DB_URL,javaxPersistenceJdbcUrl);
200         logPropertyValue(StateManagementProperties.DB_USER,javaxPersistenceJdbcUser);
201         logPropertyValue(StateManagementProperties.DB_PWD,javaxPersistenceJdbcPassword);
202                 
203         subsystemTestProperties = stateManagementProperties;
204
205         // Now that we've validated the properties, create Drools Integrity Monitor
206         // with these properties.
207         im = new DroolsPDPIntegrityMonitor(resourceName,
208                                 stateManagementProperties);
209         logger.info("init: New DroolsPDPIntegrityMonitor instantiated, resourceName = ", resourceName);
210
211         // create http server
212         try {
213                 logger.info("init: Starting HTTP server, addr= {}", testHost+":"+testPort);
214                 IntegrityMonitorRestServer server = new IntegrityMonitorRestServer();
215                 
216                 server.init(stateManagementProperties);
217         } catch (Exception e) {
218                 logger.error("init: Caught Exception attempting to start server on testPort= {} message:",
219                                                                 testPort, e);
220                 throw e;
221         }
222         logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor");
223         return im;
224   }
225
226   /**
227    * Run tests (audits) unique to Drools PDP VM (Database + Repository)
228    */
229   @Override
230         public void subsystemTest() throws IntegrityMonitorException
231   {
232         logger.info("DroolsPDPIntegrityMonitor.subsystemTest called");
233
234         // clear all responses (non-null values indicate an error)
235         for (AuditBase audit : audits)
236           {
237                 audit.setResponse(null);
238           }
239
240         // invoke all of the audits
241         for (AuditBase audit : audits)
242           {
243                 try
244                   {
245                         // invoke the audit (responses are stored within the audit object)
246                         audit.invoke(subsystemTestProperties);
247                   }
248                 catch (Exception e)
249                   {
250                         logger.error("{} audit error", audit.getName(), e);
251                         if (audit.getResponse() == null)
252                           {
253                                 // if there is no current response, use the exception message
254                                 audit.setResponse(e.getMessage());
255                           }
256                   }
257           }
258         
259           // will contain list of subsystems where the audit failed
260           String responseMsg = "";
261
262           // Loop through all of the audits, and see which ones have failed.
263           // NOTE: response information is stored within the audit objects
264           // themselves -- only one can run at a time.
265           for (AuditBase audit : audits)
266                 {
267                   String response = audit.getResponse();
268                   if (response != null)
269                         {
270                           // the audit has failed -- add subsystem and 
271                           // and 'responseValue' with the new information
272                           responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response);
273                         }
274                 }
275           
276           if(!responseMsg.isEmpty()){
277                   throw new IntegrityMonitorException(responseMsg);
278           }
279   }
280
281   /* ============================================================ */
282
283   /**
284    * This is the base class for audits invoked in 'subsystemTest'
285    */
286   public abstract static class AuditBase
287   {
288         // name of the audit
289         protected String name;
290
291         // non-null indicates the error response
292         protected String response;
293
294         /**
295          * Constructor - initialize the name, and clear the initial response
296          * @param name name of the audit
297          */
298         public AuditBase(String name)
299         {
300           this.name = name;
301           this.response = null;
302         }
303
304         /**
305          * @return the name of this audit
306          */
307         public String getName()
308         {
309           return name;
310         }
311
312         /**
313          * @return the response String (non-null indicates the error message)
314          */
315         public String getResponse()
316         {
317           return response;
318         }
319
320         /**
321          * Set the response string to the specified value
322          * @param value the new value of the response string (null = no errors)
323          */
324         public void setResponse(String value)
325         {
326           response = value;
327         }
328
329         /**
330          * Abstract method to invoke the audit
331          * @param persistenceProperties Used for DB access
332          * @throws Exception passed in by the audit
333          */
334         abstract void invoke(Properties persistenceProperties) throws Exception;
335   }
336   
337         public static class IntegrityMonitorRestServer implements Startable {
338                 protected volatile HttpServletServer server = null;
339                 protected volatile Properties integrityMonitorRestServerProperties = null;
340                 
341                 public void init(Properties props) {
342                         this.integrityMonitorRestServerProperties = props;
343                         this.start();
344                 }
345                 
346                 @Override
347                 public boolean start() {
348                         try {
349                                 ArrayList<HttpServletServer> servers = HttpServletServer.factory.build(integrityMonitorRestServerProperties);
350                                 
351                                 if (!servers.isEmpty()) {
352                                         server = servers.get(0);
353                                         
354                                         waitServerStart();
355                                 }
356                         } catch (Exception e) {
357                                 logger.error("Exception building servers", e);
358                                 return false;
359                         }
360                         
361                         return true;
362                 }
363
364                 private void waitServerStart() {
365                         try {
366                                 server.waitedStart(5);
367                         } catch (Exception e) {
368                                 logger.error("Exception waiting for servers to start: ", e);
369                         }
370                 }
371
372                 @Override
373                 public boolean stop() {
374                         try {
375                                 server.stop();
376                         } catch (Exception e) {
377                                 logger.error("Exception during stop", e);
378                         }
379                         
380                         return true;
381                 }
382
383                 @Override
384                 public void shutdown() {
385                         this.stop();
386                 }
387                 
388                 @Override
389                 public synchronized boolean isAlive() {
390                         return this.integrityMonitorRestServerProperties != null;
391                 }
392         }
393
394         public static DroolsPDPIntegrityMonitor getInstance() throws Exception{
395                 if(logger.isDebugEnabled()){
396                         logger.debug("getInstance() called");
397                 }
398                 if (im == null) {
399                         String msg = "No DroolsPDPIntegrityMonitor instance exists."
400                                         + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)";
401                         throw new Exception(msg);
402                 }else{
403                         return im;
404                 }
405         }
406 }