Addition of State Management Feature 55/11155/7
authorMagnusen, Drew (dm741q) <dm741q@att.com>
Thu, 7 Sep 2017 13:55:17 +0000 (08:55 -0500)
committerKevin McKiou <km097d@att.com>
Thu, 14 Sep 2017 18:45:36 +0000 (18:45 +0000)
Patch 1:This commit adds the feature to provide node state management.
There are also a couple of very minor cleanup items in
feature-session-persistence which came up during review and testing.
Patch 2: Cleaned up some logging statements and exceptions per
comments by Pam Dragosh. Patch 3: Clean up per comments from
Jorge Hernandez. Patch4: Added a default to ignoreErrors in
RepositoryAudit. Patch 5: Rebase.  Patch 6: Removed
api-state-management/.gitignore

Issue-ID: POLICY-155
Change-Id: I4fbfa33314d488ff46764931ca965f802b6a26d5
Signed-off-by: Kevin McKiou <km097d@att.com>
24 files changed:
.gitignore [deleted file]
api-state-management/pom.xml [new file with mode: 0644]
api-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeatureAPI.java [new file with mode: 0644]
feature-session-persistence/src/assembly/assemble_zip.xml
feature-session-persistence/src/main/feature/db/sessionpersistence/sql/18020-sessionpersistence.upgrade.sql
feature-state-management/pom.xml [new file with mode: 0644]
feature-state-management/src/assembly/assemble_zip.xml [new file with mode: 0644]
feature-state-management/src/main/feature/config/feature-state-management.properties [new file with mode: 0644]
feature-state-management/src/main/feature/db/statemanagement/sql/18020-statemanagement.upgrade.sql [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DbAudit.java [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DroolsPDPIntegrityMonitor.java [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/IntegrityMonitorRestManager.java [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/RepositoryAudit.java [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeature.java [new file with mode: 0644]
feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementProperties.java [new file with mode: 0644]
feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.core.PolicySessionFeatureAPI [new file with mode: 0644]
feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureAPI [new file with mode: 0644]
feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.statemanagement.StateManagementFeatureAPI [new file with mode: 0644]
feature-state-management/src/test/java/org/onap/policy/drools/statemanagement/test/StateManagementTest.java [new file with mode: 0644]
feature-state-management/src/test/resources/META-INF/persistence.xml [new file with mode: 0644]
feature-state-management/src/test/resources/feature-state-management.properties [new file with mode: 0644]
feature-state-management/src/test/resources/logback-test.xml [new file with mode: 0644]
packages/install/pom.xml
pom.xml

diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index 30e6052..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-.DS_Store
-.project
-.settings
-.classpath
-.jupiter
-.pydevproject
-*.swp
-*.log
-*.out
-.metadata/
-target/
-*/logs/
-*/sql/
-*/testingLogs/
-*/config/
diff --git a/api-state-management/pom.xml b/api-state-management/pom.xml
new file mode 100644 (file)
index 0000000..f5c1e21
--- /dev/null
@@ -0,0 +1,62 @@
+<!--
+  ============LICENSE_START=======================================================
+  ONAP Policy Engine - Drools PDP
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+         
+  <modelVersion>4.0.0</modelVersion>
+  
+  <parent>
+    <groupId>org.onap.policy.drools-pdp</groupId>
+    <artifactId>drools-pdp</artifactId>
+    <version>1.1.0-SNAPSHOT</version>
+  </parent>
+  
+  <artifactId>api-state-management</artifactId>
+  
+  <name>api-state-management</name>
+  <description>Separately loadable module for state management APIe</description>
+
+  <properties>
+          <maven.compiler.source>1.8</maven.compiler.source>
+          <maven.compiler.target>1.8</maven.compiler.target>
+          <swagger.version>1.5.0</swagger.version>
+  </properties>
+
+  <build>
+    <plugins>
+               <!-- none -->
+    </plugins>
+  </build>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.onap.policy.drools-pdp</groupId>
+      <artifactId>policy-core</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.onap.policy.common</groupId>
+      <artifactId>integrity-monitor</artifactId>
+      <version>${common-modules.version}</version>
+    </dependency>
+   </dependencies>
+</project>
diff --git a/api-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeatureAPI.java b/api-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeatureAPI.java
new file mode 100644 (file)
index 0000000..a6d808c
--- /dev/null
@@ -0,0 +1,182 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-core
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.util.Observer;
+
+import org.onap.policy.common.im.StandbyStatusException;
+import org.onap.policy.common.im.StateManagement;
+import org.onap.policy.drools.properties.Lockable;
+import org.onap.policy.drools.utils.OrderedService;
+import org.onap.policy.drools.utils.OrderedServiceImpl;
+
+/**
+ * This interface provides a way to invoke optional features at various
+ * points in the code. At appropriate points in the
+ * application, the code iterates through this list, invoking these optional
+ * methods. Most of the methods here are notification only -- these tend to
+ * return a 'void' value. In other cases, such as 'activatePolicySession',
+ * may 
+ */
+public interface StateManagementFeatureAPI extends OrderedService, Lockable
+{
+       
+       public static final String LOCKED               = StateManagement.LOCKED;
+         public static final String UNLOCKED             = StateManagement.UNLOCKED;
+         public static final String ENABLED              = StateManagement.ENABLED;
+         public static final String DISABLED             = StateManagement.DISABLED;
+         public static final String ENABLE_NOT_FAILED    = StateManagement.ENABLE_NOT_FAILED;
+         public static final String DISABLE_FAILED       = StateManagement.DISABLE_FAILED;
+         public static final String FAILED               = StateManagement.FAILED;
+         public static final String DEPENDENCY           = StateManagement.DEPENDENCY;
+         public static final String DEPENDENCY_FAILED    = StateManagement.DEPENDENCY_FAILED;
+         public static final String DISABLE_DEPENDENCY   = StateManagement.DISABLE_DEPENDENCY;
+         public static final String ENABLE_NO_DEPENDENCY = StateManagement.ENABLE_NO_DEPENDENCY;
+         public static final String NULL_VALUE           = StateManagement.NULL_VALUE;
+         public static final String LOCK                 = StateManagement.LOCK;
+         public static final String UNLOCK               = StateManagement.UNLOCK;
+         public static final String PROMOTE              = StateManagement.PROMOTE;
+         public static final String DEMOTE               = StateManagement.DEMOTE;
+         public static final String HOT_STANDBY          = StateManagement.HOT_STANDBY;
+         public static final String COLD_STANDBY         = StateManagement.COLD_STANDBY;
+         public static final String PROVIDING_SERVICE    = StateManagement.PROVIDING_SERVICE;
+         
+         public static final String ADMIN_STATE     = StateManagement.ADMIN_STATE;
+         public static final String OPERATION_STATE = StateManagement.OPERATION_STATE;
+         public static final String AVAILABLE_STATUS= StateManagement.AVAILABLE_STATUS;
+         public static final String STANDBY_STATUS  = StateManagement.STANDBY_STATUS;
+         
+         public static final int SEQ_NUM = 0;
+  /**
+   * 'FeatureAPI.impl.getList()' returns an ordered list of objects
+   * implementing the 'FeatureAPI' interface.
+   */
+  static public OrderedServiceImpl<StateManagementFeatureAPI> impl =
+       new OrderedServiceImpl<StateManagementFeatureAPI>(StateManagementFeatureAPI.class);
+
+  /**
+   * This method is called to add an Observer to receive notifications of state changes
+   * 
+   * @param stateChangeObserver
+   */
+  public void addObserver(Observer stateChangeObserver);
+
+  /**
+   * This method returns the X.731 Administrative State for this resource
+   * 
+   * @return String (locked, unlocked)
+   */
+  public String getAdminState();
+  
+  /**
+   * This method returns the X.731 Operational State for this resource
+   * 
+   * @return String (enabled, disabled)
+   */
+  public String getOpState();
+  
+  /**
+   * This method returns the X.731 Availability Status for this resource
+   * 
+   * @return String (failed; dependency; dependency,failed)
+   */
+  public String getAvailStatus();
+    
+  /**
+   * This method returns the X.731 Standby Status for this resource
+   * 
+   * @return String (providingservice, hotstandby or coldstandby)
+   */
+  public String getStandbyStatus();
+  
+  /**
+   * This method returns the X.731 Standby Status for the named resource
+   * @param String (resourceName)
+   * @return String (providingservice, hotstandby or coldstandby)
+   */
+  public String getStandbyStatus(String resourceName);
+  
+  /**
+   * This method moves the X.731 Operational State for the named resource
+   * into a value of disabled and the Availability Status to a value of failed.
+   * As a consequence the Standby Status value will take a value of coldstandby.
+   * 
+   * @param String (resourceName)
+   * @throws Exception 
+   */
+  public void disableFailed(String resourceName) throws Exception;
+  
+  /**
+   * This method moves the X.731 Operational State for this resource
+   * into a value of disabled and the Availability Status to a value of failed.
+   * As a consequence the Standby Status value will take a value of coldstandby.
+   * 
+   * @param String (resourceName)
+   * @throws Exception 
+   */
+  public void disableFailed() throws Exception;
+  
+  /**
+   * This method moves the X.731 Standby Status for this resource from hotstandby 
+   * to providingservice. If the current value is coldstandby, no change is made.
+   * If the current value is null, it will move to providingservice assuming the
+   * Operational State is enabled and Administrative State is unlocked.
+   * @throws Exception 
+   * @throws StandbyStatusException 
+   */
+  public void promote() throws StandbyStatusException, Exception;
+  
+  /**
+   * This method moves the X.731 Standby Status for this resource from providingservice 
+   * to hotstandby. If the current value is null, it will move to hotstandby assuming the
+   * Operational State is enabled and Administrative State is unlocked. Else, it will move
+   * to coldstandby
+   * @throws Exception 
+   */
+  public void demote() throws Exception;
+  
+  /**
+   * This method returns the resourceName associated with this instance of the StateManagementFeature 
+   * @return String (resourceName)
+   */
+  public String getResourceName();
+
+  /**
+   * This Lockable method will lock the StateManagement object Admin state
+   * @return true if successfull, false otherwise
+   */
+  @Override
+  public boolean lock();
+  
+  /**
+   * This Lockable method will unlock the StateManagement object Admin state
+   * @return true if successfull, false otherwise
+   */
+  @Override
+  public boolean unlock();
+
+  /**
+   * This Lockable method indicates the Admin state StateManagement object 
+   * @return true if locked, false otherwise
+   */
+  @Override
+  public boolean isLocked();
+}
index 1cc3ce5..8a31596 100644 (file)
@@ -24,7 +24,7 @@
        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
-       <id>session-persistence</id>
+       <id>feature-session-persistence</id>
        <formats>
                <format>zip</format>
        </formats>
index 0e98096..5d4993f 100644 (file)
@@ -51,10 +51,4 @@ WORKITEMBYTEARRAY BLOB,
 PRIMARY KEY (WORKITEMID)
 );
 
-CREATE TABLE IF NOT EXISTS sessionpersistence.SESSIONINFO_ID_SEQ (next_val bigint) engine=MyISAM;
-INSERT INTO sessionpersistence.SESSIONINFO_ID_SEQ (next_val) SELECT 1 WHERE NOT EXISTS (SELECT * FROM sessionpersistence.SESSIONINFO_ID_SEQ);
-
-CREATE TABLE IF NOT EXISTS sessionpersistence.WORKITEMINFO_ID_SEQ (next_val bigint) engine=MyISAM;
-INSERT INTO sessionpersistence.WORKITEMINFO_ID_SEQ (next_val) SELECT 1 WHERE NOT EXISTS (SELECT * FROM sessionpersistence.WORKITEMINFO_ID_SEQ);
-
 set foreign_key_checks=1;
\ No newline at end of file
diff --git a/feature-state-management/pom.xml b/feature-state-management/pom.xml
new file mode 100644 (file)
index 0000000..5265cdb
--- /dev/null
@@ -0,0 +1,137 @@
+<!--
+  ============LICENSE_START=======================================================
+  feature-state-management
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+       <modelVersion>4.0.0</modelVersion>
+
+       <parent>
+               <groupId>org.onap.policy.drools-pdp</groupId>
+               <artifactId>drools-pdp</artifactId>
+               <version>1.1.0-SNAPSHOT</version>
+       </parent>
+
+       <artifactId>feature-state-management</artifactId>
+
+       <name>feature-state-management</name>
+       <description>Separately loadable module for State Management</description>
+
+       <build>
+               <plugins>
+                       <plugin>
+                               <artifactId>maven-assembly-plugin</artifactId>
+                               <version>2.6</version>
+                               <executions>
+                                       <execution>
+                                               <id>zipfile</id>
+                                               <goals>
+                                                       <goal>single</goal>
+                                               </goals>
+                                               <phase>package</phase>
+                                               <configuration>
+                                                       <attach>true</attach>
+                                                       <finalName>${project.artifactId}-${project.version}</finalName>
+                                                       <descriptors>
+                                                               <descriptor>src/assembly/assemble_zip.xml</descriptor>
+                                                       </descriptors>
+                                                       <appendAssemblyId>false</appendAssemblyId>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+                       <plugin>
+                               <groupId>org.apache.maven.plugins</groupId>
+                               <artifactId>maven-dependency-plugin</artifactId>
+                               <version>2.8</version>
+                               <executions>
+                                       <execution>
+                                               <id>copy-dependencies</id>
+                                               <goals>
+                                                       <goal>copy-dependencies</goal>
+                                               </goals>
+                                               <phase>prepare-package</phase>
+                                               <configuration>
+                                                       <transitive>false</transitive>
+                                                       <outputDirectory>${project.build.directory}/assembly/lib</outputDirectory>
+                                                       <overWriteReleases>false</overWriteReleases>
+                                                       <overWriteSnapshots>true</overWriteSnapshots>
+                                                       <overWriteIfNewer>true</overWriteIfNewer>
+                                                       <useRepositoryLayout>false</useRepositoryLayout>
+                                                       <addParentPoms>false</addParentPoms>
+                                                       <copyPom>false</copyPom>
+                                                       <includeScope>runtime</includeScope>
+                                                       <excludeTransitive>true</excludeTransitive>
+                                               </configuration>
+                                       </execution>
+                               </executions>
+                       </plugin>
+               </plugins>
+       </build>
+
+       <dependencies>
+               <dependency>
+                       <groupId>io.swagger</groupId>
+                       <artifactId>swagger-jersey2-jaxrs</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.onap.policy.drools-pdp</groupId>
+                       <artifactId>policy-core</artifactId>
+                       <version>${project.version}</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.onap.policy.drools-pdp</groupId>
+                       <artifactId>policy-management</artifactId>
+                       <version>${project.version}</version>
+                       <scope>provided</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.onap.policy.drools-pdp</groupId>
+                       <artifactId>api-state-management</artifactId>
+                       <version>${project.version}</version>
+               </dependency>
+
+               <dependency>
+                       <groupId>com.h2database</groupId>
+                       <artifactId>h2</artifactId>
+                       <version>[1.4.186,)</version>
+                       <scope>test</scope>
+               </dependency>
+               <dependency>
+                       <groupId>org.eclipse.persistence</groupId>
+                       <artifactId>eclipselink</artifactId>
+                       <scope>provided</scope>
+               </dependency>
+               <!-- Need to pull in to assembly -->
+               <dependency>
+                       <groupId>org.onap.policy.common</groupId>
+                       <artifactId>integrity-monitor</artifactId>
+                       <version>${common-modules.version}</version>
+               </dependency>
+               <!-- Need to pull into assembly for IntegrityMonitor -->
+               <dependency>
+                       <groupId>log4j</groupId>
+                       <artifactId>log4j</artifactId>
+                       <version>1.2.17</version>
+               </dependency>
+       </dependencies>
+</project>
diff --git a/feature-state-management/src/assembly/assemble_zip.xml b/feature-state-management/src/assembly/assemble_zip.xml
new file mode 100644 (file)
index 0000000..f398829
--- /dev/null
@@ -0,0 +1,76 @@
+<!--
+  ============LICENSE_START=======================================================
+  feature-state-management
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<!-- Defines how we build the .zip file which is our distribution. -->
+
+<assembly
+       xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
+       <id>feature-state-management</id>
+       <formats>
+               <format>zip</format>
+       </formats>
+
+       <!-- we want "system" and related files right at the root level as this 
+               file is suppose to be unzip on top of a karaf distro. -->
+       <includeBaseDirectory>false</includeBaseDirectory>
+
+       <fileSets>
+               <fileSet>
+                       <directory>target</directory>
+                       <outputDirectory>lib/feature</outputDirectory>
+                       <includes>
+                               <include>feature-state-management-${project.version}.jar</include>
+                       </includes>
+               </fileSet>
+               <fileSet>
+                       <directory>target/assembly/lib</directory>
+                       <outputDirectory>lib/dependencies</outputDirectory>
+                       <includes>
+                               <include>*.jar</include>
+                       </includes>
+               </fileSet>
+               <fileSet>
+                       <directory>src/main/feature/config</directory>
+                       <outputDirectory>config</outputDirectory>
+                       <fileMode>0644</fileMode>
+                       <excludes/>
+               </fileSet>
+               <fileSet>
+                       <directory>src/main/feature/bin</directory>
+                       <outputDirectory>bin</outputDirectory>
+                       <fileMode>0744</fileMode>
+                       <excludes/>
+               </fileSet>
+               <fileSet>
+                       <directory>src/main/feature/db</directory>
+                       <outputDirectory>db</outputDirectory>
+                       <fileMode>0744</fileMode>
+                       <excludes/>
+               </fileSet>
+               <fileSet>
+                       <directory>src/main/feature/install</directory>
+                       <outputDirectory>install</outputDirectory>
+                       <fileMode>0744</fileMode>
+                       <excludes/>
+               </fileSet>
+       </fileSets>
+</assembly>
diff --git a/feature-state-management/src/main/feature/config/feature-state-management.properties b/feature-state-management/src/main/feature/config/feature-state-management.properties
new file mode 100644 (file)
index 0000000..72c1fe2
--- /dev/null
@@ -0,0 +1,82 @@
+###
+# ============LICENSE_START=======================================================
+# feature-state-management
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# DB properties
+javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver
+javax.persistence.jdbc.url=jdbc:mariadb://${{SQL_HOST}}:3306/statemanagement
+javax.persistence.jdbc.user=${{SQL_USER}}
+javax.persistence.jdbc.password=${{SQL_PASSWORD}}
+
+# DroolsPDPIntegrityMonitor Properties
+hostPort=0.0.0.0:57692
+
+#IntegrityMonitor Properties
+
+# Must be unique across the system
+resource.name=pdp1
+# Name of the site in which this node is hosted 
+site_name=site1
+# Forward Progress Monitor update interval seconds
+fp_monitor_interval=30
+# Failed counter threshold before failover 
+failed_counter_threshold=3
+# Interval between test transactions when no traffic seconds
+test_trans_interval=10
+# Interval between writes of the FPC to the DB seconds 
+write_fpc_interval=5
+# Node type Note: Make sure you don't leave any trailing spaces, or you'll get an 'invalid node type' error! 
+node_type=pdp_drools
+# Dependency groups are groups of resources upon which a node operational state is dependent upon. 
+# Each group is a comma-separated list of resource names and groups are separated by a semicolon.  For example:
+# dependency_groups=site_1.astra_1,site_1.astra_2;site_1.brms_1,site_1.brms_2;site_1.logparser_1;site_1.pypdp_1
+dependency_groups=
+# When set to true, dependent health checks are performed by using JMX to invoke test() on the dependent.
+# The default false is to use state checks for health.
+test_via_jmx=true
+# This is the max number of seconds beyond which a non incrementing FPC is considered a failure
+max_fpc_update_interval=120
+# Run the state audit every 60 seconds (60000 ms).  The state audit finds stale DB entries in the 
+# forwardprogressentity table and marks the node as disabled/failed in the statemanagemententity 
+# table. NOTE! It will only run on nodes that have a standbystatus = providingservice.
+# A value of <= 0 will turn off the state audit.
+state_audit_interval_ms=60000
+# The refresh state audit is run every (default) 10 minutes (600000 ms) to clean up any state corruption in the 
+# DB statemanagemententity table. It only refreshes the DB state entry for the local node.  That is, it does not
+# refresh the state of any other nodes.  A value <= 0 will turn the audit off. Any other value will override 
+# the default of 600000 ms.
+refresh_state_audit_interval_ms=600000
+
+
+# Repository audit properties
+
+# Assume it's the releaseRepository that needs to be audited,
+# because that's the one BRMGW will publish to.
+repository.audit.id=${{releaseRepositoryID}}
+repository.audit.url=${{releaseRepositoryUrl}}
+repository.audit.username=${{repositoryUsername}}
+repository.audit.password=${{repositoryPassword}}
+# Flag to control the execution of the subsystemTest for the Nexus Maven repository
+repository.audit.is.active=false
+repository.audit.ignore.errors=true
+
+# DB Audit Properties
+
+# Flag to control the execution of the subsystemTest for the Database
+db.audit.is.active=false
\ No newline at end of file
diff --git a/feature-state-management/src/main/feature/db/statemanagement/sql/18020-statemanagement.upgrade.sql b/feature-state-management/src/main/feature/db/statemanagement/sql/18020-statemanagement.upgrade.sql
new file mode 100644 (file)
index 0000000..f73f992
--- /dev/null
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+set foreign_key_checks=0; 
+
+CREATE TABLE if not exists statemanagement.StateManagementEntity
+(
+  id           int not null auto_increment, 
+  resourceName varchar(100) not null, 
+  adminState   varchar(20) not null, 
+  opstate      varchar(20) not null, 
+  availStatus  varchar(20), 
+  standbyStatus varchar(20), 
+  created_date timestamp not null default current_timestamp,
+  modifiedDate timestamp not null,
+  primary key(id), 
+  unique key resource(resourceName)
+);  
+
+CREATE TABLE if not exists statemanagement.ResourceRegistrationEntity
+(
+  resourceRegistrationId bigint not null auto_increment, 
+  resourceName varchar(100)  not null, 
+  resourceURL varchar(255)   not null, 
+  site varchar(50), 
+  nodetype varchar(50), 
+  created_date timestamp     not null default current_timestamp,
+  last_updated timestamp     not null, 
+  primary key (resourceRegistrationId), 
+  unique key  resource (resourceName), 
+  unique  key id_resource_url (resourceURL)
+); 
+
+CREATE TABLE if not exists statemanagement.ForwardProgressEntity
+(
+  forwardProgressId bigint not null auto_increment,
+  resourceName varchar(100)  not null, 
+  fpc_count    bigint        not null, 
+  created_date timestamp     not null default current_timestamp,
+  last_updated timestamp     not null, 
+  primary key (forwardProgressId), 
+  unique key resource_key (resourceName)
+);
+
+CREATE TABLE if not exists statemanagement.sequence
+(
+SEQ_NAME VARCHAR(50) NOT NULL,
+SEQ_COUNT DECIMAL(38,0),
+PRIMARY KEY (SEQ_NAME)
+);
+
+-- Will only insert a record if none exists:
+INSERT INTO statemanagement.SEQUENCE (SEQ_NAME,SEQ_COUNT) 
+SELECT * FROM (SELECT 'SEQ_GEN',1) AS tmp
+WHERE NOT EXISTS(select SEQ_NAME from statemanagement.SEQUENCE where SEQ_NAME = 'SEQ_GEN') LIMIT 1;
+
+set foreign_key_checks=1;
\ No newline at end of file
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DbAudit.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DbAudit.java
new file mode 100644 (file)
index 0000000..a86ac8e
--- /dev/null
@@ -0,0 +1,218 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.util.Properties;
+import java.util.UUID;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class audits the database
+ */
+public class DbAudit extends DroolsPDPIntegrityMonitor.AuditBase
+{
+       // get an instance of logger 
+  private static Logger  logger = LoggerFactory.getLogger(DbAudit.class);      
+  // single global instance of this audit object
+  final static private DbAudit instance = new DbAudit();
+
+  // This indicates if 'CREATE TABLE IF NOT EXISTS Audit ...' should be
+  // invoked -- doing this avoids the need to create the table in advance.
+  static private boolean createTableNeeded = true;
+
+  /**
+   * @return the single 'DbAudit' instance
+   */
+  static DroolsPDPIntegrityMonitor.AuditBase getInstance()
+  {
+       return(instance);
+  }
+
+  /**
+   * Constructor - set the name to 'Database'
+   */
+  private DbAudit()
+  {
+       super("Database");
+  }
+
+  /**
+   * Invoke the audit
+   *
+   * @param properties properties to be passed to the audit
+   */
+  @Override
+       public void invoke(Properties properties)
+  {
+       if(logger.isDebugEnabled()){
+               logger.debug("Running 'DbAudit.invoke'");
+       }
+       boolean isActive = true;
+       String dbAuditIsActive = StateManagementProperties.getProperty("db.audit.is.active");
+       if(logger.isDebugEnabled()){
+               logger.debug("DbAudit.invoke: dbAuditIsActive = {}", dbAuditIsActive);
+       }
+       
+       if (dbAuditIsActive != null) {
+               try {
+                       isActive = Boolean.parseBoolean(dbAuditIsActive.trim());
+               } catch (NumberFormatException e) {
+                       logger.warn("DbAudit.invoke: Ignoring invalid property: db.audit.is.active = {}", dbAuditIsActive);
+               }
+       }
+       
+       if(!isActive){
+               
+               logger.info("DbAudit.invoke: exiting because isActive = {}", isActive);
+               return;
+       }
+       
+       // fetch DB properties from properties file -- they are already known
+       // to exist, because they were verified by the 'IntegrityMonitor'
+       // constructor
+       String url = properties.getProperty(StateManagementProperties.DB_URL);
+       String user = properties.getProperty(StateManagementProperties.DB_USER);
+       String password = properties.getProperty(StateManagementProperties.DB_PWD);
+
+       // connection to DB
+       Connection connection = null;
+
+       // supports SQL operations
+       PreparedStatement statement = null;
+       ResultSet rs = null;
+
+       // operation phase currently running -- used to construct an error
+       // message, if needed
+       String phase = null;
+
+       try
+         {
+               // create connection to DB
+               phase = "creating connection";
+               if(logger.isDebugEnabled()){
+                       logger.debug("DbAudit: Creating connection to {}", url);
+               }
+
+               connection = DriverManager.getConnection(url, user, password);
+
+               // create audit table, if needed
+               if (createTableNeeded)
+                 {
+                       phase = "create table";
+                       if(logger.isDebugEnabled()){
+                               logger.info("DbAudit: Creating 'Audit' table, if needed");
+                       }
+                       statement = connection.prepareStatement
+                         ("CREATE TABLE IF NOT EXISTS Audit (\n"
+                          + " name varchar(64) DEFAULT NULL,\n"
+                          + " UNIQUE KEY name (name)\n"
+                          + ") DEFAULT CHARSET=latin1;");
+                       statement.execute();
+                       statement.close();
+                       createTableNeeded = false;
+                 }
+
+               // insert an entry into the table
+               phase = "insert entry";
+               String key = UUID.randomUUID().toString();
+               statement = connection.prepareStatement
+                 ("INSERT INTO Audit (name) VALUES (?)");
+               statement.setString(1, key);
+               statement.executeUpdate();
+               statement.close();
+
+               // fetch the entry from the table
+               phase = "fetch entry";
+               statement = connection.prepareStatement
+                 ("SELECT name FROM Audit WHERE name = ?");
+               statement.setString(1, key);
+               rs = statement.executeQuery();
+               if (rs.first())
+                 {
+                       // found entry
+                       if(logger.isDebugEnabled()){
+                               logger.debug("DbAudit: Found key {}", rs.getString(1));
+                       }
+                 }
+               else
+                 {
+                       logger.error
+                         ("DbAudit: can't find newly-created entry with key {}", key);
+                       setResponse("Can't find newly-created entry");
+                 }
+               statement.close();
+
+               // delete entries from table
+               phase = "delete entry";
+               statement = connection.prepareStatement
+                 ("DELETE FROM Audit WHERE name = ?");
+               statement.setString(1, key);
+               statement.executeUpdate();
+               statement.close();
+               statement = null;
+         }
+       catch (Exception e)
+         {
+               String message = "DbAudit: Exception during audit, phase = " + phase;
+               logger.error(message, e);
+               setResponse(message);
+         }
+       finally
+         {
+               if (rs != null)
+                 {
+                       try
+                         {
+                               rs.close();
+                         }
+                       catch (Exception e)
+                         {
+                         }
+                 }
+               if (statement != null)
+                 {
+                       try
+                         {
+                               statement.close();
+                         }
+                       catch (Exception e)
+                         {
+                         }
+                 }
+               if (connection != null)
+                 {
+                       try
+                         {
+                               connection.close();
+                         }
+                       catch (Exception e)
+                         {
+                         }
+                 }
+         }
+  }
+}
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DroolsPDPIntegrityMonitor.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/DroolsPDPIntegrityMonitor.java
new file mode 100644 (file)
index 0000000..73f6f73
--- /dev/null
@@ -0,0 +1,398 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Properties;
+
+import org.onap.policy.common.im.IntegrityMonitor;
+import org.onap.policy.common.im.IntegrityMonitorException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.onap.policy.drools.core.PolicyContainer;
+import org.onap.policy.drools.http.server.HttpServletServer;
+import org.onap.policy.drools.properties.Startable;
+import org.onap.policy.drools.utils.PropertyUtil;
+
+/**
+ * This class extends 'IntegrityMonitor' for use in the 'Drools PDP'
+ * virtual machine. The included audits are 'Database' and 'Repository'.
+ */
+public class DroolsPDPIntegrityMonitor extends IntegrityMonitor
+{
+       
+       // get an instance of logger 
+  private static final Logger  logger = LoggerFactory.getLogger(DroolsPDPIntegrityMonitor.class);      
+
+  // static global instance
+  static private DroolsPDPIntegrityMonitor im = null;
+
+  // list of audits to run
+  static private AuditBase[] audits =
+       new AuditBase[]{DbAudit.getInstance(), RepositoryAudit.getInstance()};
+  
+  static private Properties subsystemTestProperties = null;
+
+  static private final String PROPERTIES_NAME = "feature-state-management.properties";
+  /**
+   * Static initialization -- create Drools Integrity Monitor, and
+   * an HTTP server to handle REST 'test' requests
+   */
+  static public DroolsPDPIntegrityMonitor init(String configDir) throws Exception
+  {
+                 
+       logger.info("init: Entering and invoking PropertyUtil.getProperties() on '{}'", configDir);
+               
+       // read in properties
+       Properties stateManagementProperties =
+         PropertyUtil.getProperties(configDir + "/" + PROPERTIES_NAME);
+       
+       subsystemTestProperties = stateManagementProperties;
+       
+               // fetch and verify definitions of some properties
+       // (the 'IntegrityMonitor' constructor does some additional verification)
+       
+       String resourceName = stateManagementProperties.getProperty("resource.name");
+       String hostPort = stateManagementProperties.getProperty("hostPort");
+       String fpMonitorInterval = stateManagementProperties.getProperty("fp_monitor_interval");
+       String failedCounterThreshold = stateManagementProperties.getProperty("failed_counter_threshold");
+       String testTransInterval = stateManagementProperties.getProperty("test_trans_interval");
+       String writeFpcInterval = stateManagementProperties.getProperty("write_fpc_interval");
+       String siteName = stateManagementProperties.getProperty("site_name");
+       String nodeType = stateManagementProperties.getProperty("node_type");
+       String dependencyGroups = stateManagementProperties.getProperty("dependency_groups");
+       String javaxPersistenceJdbcDriver = stateManagementProperties.getProperty("javax.persistence.jdbc.driver");
+       String javaxPersistenceJdbcUrl = stateManagementProperties.getProperty("javax.persistence.jdbc.url");
+       String javaxPersistenceJdbcUser = stateManagementProperties.getProperty("javax.persistence.jdbc.user");
+       String javaxPersistenceJdbcPassword = stateManagementProperties.getProperty("javax.persistence.jdbc.password");
+       
+       if (resourceName == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'resource.name'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'resource.name'"));
+         }
+       if (hostPort == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'hostPort'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'hostPort'"));
+         }
+       if (fpMonitorInterval == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'fp_monitor_interval'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'fp_monitor_interval'"));
+         }     
+       if (failedCounterThreshold == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'failed_counter_threshold'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'failed_counter_threshold'"));
+         }     
+       if (testTransInterval == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'test_trans_interval'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'test_trans_interval'"));
+         }     
+       if (writeFpcInterval == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'write_fpc_interval'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'write_fpc_interval'"));
+         }     
+       if (siteName == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'site_name'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'site_name'"));
+         }     
+       if (nodeType == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'node_type'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'node_type'"));
+         }     
+       if (dependencyGroups == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'dependency_groups'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'dependency_groups'"));
+         }     
+       if (javaxPersistenceJdbcDriver == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for xacml DB'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for xacml DB'"));
+         }             
+       if (javaxPersistenceJdbcUrl == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.url  for xacml DB'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.url  for xacml DB'"));
+         }                     
+       if (javaxPersistenceJdbcUser == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for xacml DB'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for xacml DB'"));
+         }                     
+       if (javaxPersistenceJdbcPassword == null)
+         {
+               logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.password for xacml DB'");
+               throw(new Exception
+                         ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.password'  for xacml DB'"));
+         }             
+
+       // Now that we've validated the properties, create Drools Integrity Monitor
+       // with these properties.
+       im = new DroolsPDPIntegrityMonitor(resourceName,
+                               stateManagementProperties);
+       logger.info("init: New DroolsPDPIntegrityMonitor instantiated, hostPort= {}", hostPort);
+
+       // determine host and port for HTTP server
+       int index = hostPort.lastIndexOf(':');
+       InetSocketAddress addr;
+
+       if (index < 0)
+         {
+               addr = new InetSocketAddress(Integer.valueOf(hostPort));
+         }
+       else
+         {
+               addr = new InetSocketAddress
+                 (hostPort.substring(0, index),
+                  Integer.valueOf(hostPort.substring(index + 1)));
+         }
+
+       // create http server
+       try {
+               logger.info("init: Starting HTTP server, addr= {}", addr);
+               IntegrityMonitorRestServer server = new IntegrityMonitorRestServer();
+               
+               server.init(stateManagementProperties);
+
+               System.out.println("init: Started server on hostPort=" + hostPort);
+       } catch (Exception e) {
+               logger.error("init: Caught Exception attempting to start server on hostPort= {}, message = {}",
+                                                               hostPort, e.getMessage());
+               throw e;
+
+       }
+       
+       logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor");
+       return im;
+  }
+
+  /**
+   * Constructor - pass arguments to superclass, but remember properties
+   * @param resourceName unique name of this Integrity Monitor
+   * @param url the JMX URL of the MBean server
+   * @param properties properties used locally, as well as by
+   *   'IntegrityMonitor'
+   * @throws Exception (passed from superclass)
+   */
+       private DroolsPDPIntegrityMonitor(String resourceName,
+                       Properties consolidatedProperties
+                       ) throws Exception {
+       super(resourceName, consolidatedProperties);
+  }
+
+  /**
+   * Run tests (audits) unique to Drools PDP VM (Database + Repository)
+   */
+  @Override
+       public void subsystemTest() throws IntegrityMonitorException
+  {
+       logger.info("DroolsPDPIntegrityMonitor.subsystemTest called");
+
+       // clear all responses (non-null values indicate an error)
+       for (AuditBase audit : audits)
+         {
+               audit.setResponse(null);
+         }
+
+       // invoke all of the audits
+       for (AuditBase audit : audits)
+         {
+               try
+                 {
+                       // invoke the audit (responses are stored within the audit object)
+                       audit.invoke(subsystemTestProperties);
+                 }
+               catch (Exception e)
+                 {
+                       logger.error("{} audit error", audit.getName(), e);
+                       if (audit.getResponse() == null)
+                         {
+                               // if there is no current response, use the exception message
+                               audit.setResponse(e.getMessage());
+                         }
+                 }
+         }
+       
+         // will contain list of subsystems where the audit failed
+         String responseMsg = "";
+
+         // Loop through all of the audits, and see which ones have failed.
+         // NOTE: response information is stored within the audit objects
+         // themselves -- only one can run at a time.
+         for (AuditBase audit : audits)
+               {
+                 String response = audit.getResponse();
+                 if (response != null)
+                       {
+                         // the audit has failed -- add subsystem and 
+                         // and 'responseValue' with the new information
+                         responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response);
+                       }
+               }
+         
+         if(!responseMsg.isEmpty()){
+                 throw new IntegrityMonitorException(responseMsg);
+         }
+  }
+
+  /* ============================================================ */
+
+  /**
+   * This is the base class for audits invoked in 'subsystemTest'
+   */
+  static public abstract class AuditBase
+  {
+       // name of the audit
+       protected String name;
+
+       // non-null indicates the error response
+       protected String response;
+
+       /**
+        * Constructor - initialize the name, and clear the initial response
+        * @param name name of the audit
+        */
+       public AuditBase(String name)
+       {
+         this.name = name;
+         this.response = null;
+       }
+
+       /**
+        * @return the name of this audit
+        */
+       public String getName()
+       {
+         return(name);
+       }
+
+       /**
+        * @return the response String (non-null indicates the error message)
+        */
+       public String getResponse()
+       {
+         return(response);
+       }
+
+       /**
+        * Set the response string to the specified value
+        * @param value the new value of the response string (null = no errors)
+        */
+       public void setResponse(String value)
+       {
+         response = value;
+       }
+
+       /**
+        * Abstract method to invoke the audit
+        * @param persistenceProperties Used for DB access
+        * @throws Exception passed in by the audit
+        */
+       abstract void invoke(Properties persistenceProperties) throws Exception;
+  }
+  
+       public static class IntegrityMonitorRestServer implements Startable {
+               protected volatile HttpServletServer server = null;
+               protected volatile Properties integrityMonitorRestServerProperties = null;
+               
+               public void init(Properties props) {
+                       this.integrityMonitorRestServerProperties = props;
+                       this.start();
+               }
+               
+               @Override
+               public boolean start() throws IllegalStateException {
+                       try {
+                               ArrayList<HttpServletServer> servers = HttpServletServer.factory.build(integrityMonitorRestServerProperties);
+                               
+                               if (!servers.isEmpty()) {
+                                       server = servers.get(0);
+                                       
+                                       try {
+                                               server.waitedStart(5);
+                                       } catch (Exception e) {
+                                               e.printStackTrace();
+                                       }
+                               }
+                       } catch (Exception e) {
+                               return false;
+                       }
+                       
+                       return true;
+               }
+
+               @Override
+               public boolean stop() throws IllegalStateException {
+                       try {
+                               server.stop();
+                       } catch (Exception e) {
+                               e.printStackTrace();
+                       }
+                       
+                       return true;
+               }
+
+               @Override
+               public void shutdown() throws IllegalStateException {
+                       this.stop();
+               }
+               
+               @Override
+               public synchronized boolean isAlive() {
+                       return this.integrityMonitorRestServerProperties != null;
+               }
+       }
+
+       public static DroolsPDPIntegrityMonitor getInstance() throws Exception{
+               if(logger.isDebugEnabled()){
+                       logger.debug("getInstance() called");
+               }
+               if (im == null) {
+                       String msg = "No DroolsPDPIntegrityMonitor instance exists."
+                                       + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)";
+                       throw new Exception(msg);
+               }else{
+                       return im;
+               }
+       }
+}
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/IntegrityMonitorRestManager.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/IntegrityMonitorRestManager.java
new file mode 100644 (file)
index 0000000..f502429
--- /dev/null
@@ -0,0 +1,110 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+
+@Api(value = "test")
+       @Path("/")
+public class IntegrityMonitorRestManager {
+               private static Logger logger = LoggerFactory.getLogger(IntegrityMonitorRestManager.class);      
+               private DroolsPDPIntegrityMonitor im;
+               
+               /**
+                * Test interface for Integrity Monitor
+                * 
+                * @return Exception message if exception, otherwise empty
+                */
+               @ApiOperation(
+                       value = "Test endpoint for integrity monitor",
+                       notes = "The TEST command is used to request data from a subcomponent "
+                                       + "instance that can be used to determine its operational state. "
+                                       + "A 200/success response status code should be returned if the "
+                                       + "subcomponent instance is functioning properly and able to respond to requests.",
+                       response = String.class)
+               @ApiResponses(value = {
+                       @ApiResponse(
+                               code = 200,
+                               message = "Integrity monitor sanity check passed"),
+                       @ApiResponse(
+                               code = 500,
+                               message = "Integrity monitor sanity check encountered an exception. This can indicate operational state disabled or administrative state locked")
+               })
+               @GET
+               @Path("test")
+               public Response test() {
+                       logger.error("integrity monitor /test accessed");
+                       // The responses are stored within the audit objects, so we need to
+                       // invoke the audits and get responses before we handle another
+                       // request.
+                       synchronized (IntegrityMonitorRestManager.class) {
+                               // will include messages associated with subsystem failures
+                               StringBuilder body = new StringBuilder();
+
+                               // 200=SUCCESS, 500=failure
+                               int responseValue = 200;
+
+                               if (im == null) {
+                                       try {
+                                               im = DroolsPDPIntegrityMonitor.getInstance();
+                                       } catch (Exception e) {
+                                               logger.error("IntegrityMonitorRestManager: test() interface caught an exception", e);
+                                               e.printStackTrace();
+                                               
+                                               body.append("\nException: " + e + "\n");
+                                               responseValue = 500;
+                                       }
+                               }
+
+                               if (im != null) {
+                                       try {
+                                               // call 'IntegrityMonitor.evaluateSanity()'
+                                               im.evaluateSanity();
+                                       } catch (Exception e) {
+                                               // this exception isn't coming from one of the audits,
+                                               // because those are caught in 'subsystemTest()'
+                                               logger.error("DroolsPDPIntegrityMonitor.evaluateSanity()", e);
+
+                                               // include exception in HTTP response
+                                               body.append("\nException: " + e + "\n");
+                                               responseValue = 500;
+                                       }
+                               }
+
+                               // send response, including the contents of 'body'
+                               // (which is empty if everything is successful)
+                               if (responseValue == 200)
+                                       return Response.status(Response.Status.OK).build();
+                               else
+                                       return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(body.toString()).build();
+                       }
+               }
+}
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/RepositoryAudit.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/RepositoryAudit.java
new file mode 100644 (file)
index 0000000..6171572
--- /dev/null
@@ -0,0 +1,552 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.LinkedList;
+import java.util.Properties;
+import java.util.concurrent.TimeUnit;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class audits the Maven repository
+ */
+public class RepositoryAudit extends DroolsPDPIntegrityMonitor.AuditBase
+{
+  private static final long DEFAULT_TIMEOUT = 60;      // timeout in 60 seconds
+
+  // get an instance of logger
+  private static Logger  logger = LoggerFactory.getLogger(RepositoryAudit.class);              
+  // single global instance of this audit object
+  static private RepositoryAudit instance = new RepositoryAudit();
+
+  /**
+   * @return the single 'RepositoryAudit' instance
+   */
+  static DroolsPDPIntegrityMonitor.AuditBase getInstance()
+  {
+       return(instance);
+  }
+
+  /**
+   * Constructor - set the name to 'Repository'
+   */
+  private RepositoryAudit()
+  {
+       super("Repository");
+  }
+
+  /**
+   * Invoke the audit
+   *
+   * @param properties properties to be passed to the audit
+   */
+  @Override
+       public void invoke(Properties properties)
+       throws IOException, InterruptedException
+  {
+       if(logger.isDebugEnabled()){  
+               logger.debug("Running 'RepositoryAudit.invoke'");
+       }
+       
+       boolean isActive = true;
+       boolean ignoreErrors = true;            // ignore errors by default
+       String repoAuditIsActive = StateManagementProperties.getProperty("repository.audit.is.active");
+       String repoAuditIgnoreErrors =
+         StateManagementProperties.getProperty("repository.audit.ignore.errors");
+       logger.debug("RepositoryAudit.invoke: repoAuditIsActive = {}" 
+                                + ", repoAuditIgnoreErrors = {}",repoAuditIsActive, repoAuditIgnoreErrors);
+       
+       if (repoAuditIsActive != null) {
+               try {
+                       isActive = Boolean.parseBoolean(repoAuditIsActive.trim());
+               } catch (NumberFormatException e) {
+                       logger.warn("RepositoryAudit.invoke: Ignoring invalid property: repository.audit.is.active = {}", repoAuditIsActive);
+               }
+       }
+       
+       if(!isActive){
+               logger.info("RepositoryAudit.invoke: exiting because isActive = {}", isActive);
+               return;
+       }
+
+       if (repoAuditIgnoreErrors != null)
+         {
+               try
+                 {
+                       ignoreErrors = Boolean.parseBoolean(repoAuditIgnoreErrors.trim());
+                 }
+               catch (NumberFormatException e)
+                 {
+                       ignoreErrors = true;
+                       logger.warn("RepositoryAudit.invoke: Ignoring invalid property: repository.audit.ignore.errors = {}", repoAuditIgnoreErrors);
+                 }
+         }else{
+                 ignoreErrors = true;
+         }
+
+       // Fetch repository information from 'IntegrityMonitorProperties'
+       String repositoryId =
+         StateManagementProperties.getProperty("repository.audit.id");
+       String repositoryUrl =
+         StateManagementProperties.getProperty("repository.audit.url");
+       String repositoryUsername =
+         StateManagementProperties.getProperty("repository.audit.username");
+       String repositoryPassword =
+         StateManagementProperties.getProperty("repository.audit.password");
+       boolean upload =
+         (repositoryId != null && repositoryUrl != null
+          && repositoryUsername != null && repositoryPassword != null);
+
+       // used to incrementally construct response as problems occur
+       // (empty = no problems)
+       StringBuilder response = new StringBuilder();
+
+       long timeoutInSeconds = DEFAULT_TIMEOUT;
+       String timeoutString =
+         StateManagementProperties.getProperty("repository.audit.timeout");
+       if (timeoutString != null && !timeoutString.isEmpty())
+         {
+               try
+                 {
+                       timeoutInSeconds = Long.valueOf(timeoutString);
+                 }
+               catch (NumberFormatException e)
+                 {
+                       logger.error
+                         ("RepositoryAudit: Invalid 'repository.audit.timeout' value: '{}'", timeoutString, e);
+                       if (!ignoreErrors)
+                         {
+                               response.append("Invalid 'repository.audit.timeout' value: '")
+                                 .append(timeoutString).append("'\n");
+                               setResponse(response.toString());
+                         }
+                 }
+         }
+
+       // artifacts to be downloaded
+       LinkedList<Artifact> artifacts = new LinkedList<>();
+
+       /*
+        * 1) create temporary directory
+        */
+       Path dir = Files.createTempDirectory("auditRepo");
+       logger.info("RepositoryAudit: temporary directory = {}", dir);
+
+       // nested 'pom.xml' file and 'repo' directory
+       Path pom = dir.resolve("pom.xml");
+       Path repo = dir.resolve("repo");
+
+       /*
+        * 2) Create test file, and upload to repository
+        *    (only if repository information is specified)
+        */
+       String groupId = null;
+       String artifactId = null;
+       String version = null;
+       if (upload)
+         {
+               groupId = "org.onap.policy.audit";
+               artifactId = "repository-audit";
+               version = "0." + System.currentTimeMillis();
+
+               if (repositoryUrl.toLowerCase().contains("snapshot"))
+                 {
+                       // use SNAPSHOT version
+                       version += "-SNAPSHOT";
+                 }
+
+               // create text file to write
+               FileOutputStream fos =
+                 new FileOutputStream(dir.resolve("repository-audit.txt").toFile());
+               try
+                 {
+                       fos.write(version.getBytes());
+                 }
+               finally
+                 {
+                       fos.close();
+                 }
+
+               // try to install file in repository
+               if (runProcess
+                       (timeoutInSeconds, dir.toFile(), null,
+                        "mvn", "deploy:deploy-file",
+                        "-DrepositoryId=" + repositoryId,
+                        "-Durl=" + repositoryUrl,
+                        "-Dfile=repository-audit.txt",
+                        "-DgroupId=" + groupId,
+                        "-DartifactId=" + artifactId,
+                        "-Dversion=" + version,
+                        "-Dpackaging=txt",
+                        "-DgeneratePom=false") != 0)
+                 {
+                       logger.error
+                         ("RepositoryAudit: 'mvn deploy:deploy-file' failed");
+                       if (!ignoreErrors)
+                         {
+                               response.append("'mvn deploy:deploy-file' failed\n");
+                               setResponse(response.toString());
+                         }
+                 }
+               else
+                 {
+                       logger.info
+                         ("RepositoryAudit: 'mvn deploy:deploy-file succeeded");
+
+                       // we also want to include this new artifact in the download
+                       // test (steps 3 and 4)
+                       artifacts.add(new Artifact(groupId, artifactId, version, "txt"));
+                 }
+         }
+
+       /*
+        * 3) create 'pom.xml' file in temporary directory
+        */
+       artifacts.add(new Artifact("org.apache.maven/maven-embedder/3.2.2"));
+       
+       StringBuilder sb = new StringBuilder();
+       sb.append
+         ("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+          + "         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n"
+          + "\n"
+          + "  <modelVersion>4.0.0</modelVersion>\n"
+          + "  <groupId>empty</groupId>\n"
+          + "  <artifactId>empty</artifactId>\n"
+          + "  <version>1.0-SNAPSHOT</version>\n"
+          + "  <packaging>pom</packaging>\n"
+          + "\n"
+          + "  <build>\n"
+          + "    <plugins>\n"
+          + "      <plugin>\n"
+          + "         <groupId>org.apache.maven.plugins</groupId>\n"
+          + "         <artifactId>maven-dependency-plugin</artifactId>\n"
+          + "         <version>2.10</version>\n"
+          + "         <executions>\n"
+          + "           <execution>\n"
+          + "             <id>copy</id>\n"
+          + "             <goals>\n"
+          + "               <goal>copy</goal>\n"
+          + "             </goals>\n"
+          + "             <configuration>\n"
+          + "               <localRepositoryDirectory>")
+         .append(repo)
+         .append("</localRepositoryDirectory>\n")
+         .append("               <artifactItems>\n");
+       for (Artifact artifact : artifacts)
+         {
+               // each artifact results in an 'artifactItem' element
+               sb.append
+                 ("                 <artifactItem>\n"
+                  + "                   <groupId>")
+                 .append(artifact.groupId)
+                 .append
+                 ("</groupId>\n"
+                  + "                   <artifactId>")
+                 .append(artifact.artifactId)
+                 .append
+                 ("</artifactId>\n"
+                  + "                   <version>")
+                 .append(artifact.version)
+                 .append
+                 ("</version>\n"
+                  + "                   <type>")
+                 .append(artifact.type)
+                 .append
+                 ("</type>\n"
+                  + "                 </artifactItem>\n");
+         }
+       sb.append
+         ("               </artifactItems>\n"
+          + "             </configuration>\n"
+          + "           </execution>\n"
+          + "         </executions>\n"
+          + "      </plugin>\n"
+          + "    </plugins>\n"
+          + "  </build>\n"
+          + "</project>\n");
+       FileOutputStream fos = new FileOutputStream(pom.toFile());
+       try
+         {
+               fos.write(sb.toString().getBytes());
+         }
+       finally
+         {
+               fos.close();
+         }
+
+       /*
+        * 4) Invoke external 'mvn' process to do the downloads
+        */
+
+       // output file = ${dir}/out (this supports step '4a')
+       File output = dir.resolve("out").toFile();
+
+       // invoke process, and wait for response
+       int rval = runProcess
+         (timeoutInSeconds, dir.toFile(), output, "mvn", "compile");
+       logger.info("RepositoryAudit: 'mvn' return value = {}", rval);
+       if (rval != 0)
+         {
+               logger.error
+                 ("RepositoryAudit: 'mvn compile' invocation failed");
+               if (!ignoreErrors)
+                 {
+                       response.append("'mvn compile' invocation failed\n");
+                       setResponse(response.toString());
+                 }
+         }
+
+       /*
+        * 4a) Check attempted and successful downloads from output file
+        *     Note: at present, this step just generates log messages,
+        *     but doesn't do any verification.
+        */
+       if (rval == 0)
+         {
+               // place output in 'fileContents' (replacing the Return characters
+               // with Newline)
+               byte[] outputData = new byte[(int)output.length()];
+               FileInputStream fis = new FileInputStream(output);
+               fis.read(outputData);
+               String fileContents = new String(outputData).replace('\r','\n');
+               fis.close();
+
+               // generate log messages from 'Downloading' and 'Downloaded'
+               // messages within the 'mvn' output
+               int index = 0;
+               while ((index = fileContents.indexOf("\nDown", index)) > 0)
+                 {
+                       index += 5;
+                       if (fileContents.regionMatches(index, "loading: ", 0, 9))
+                         {
+                               index += 9;
+                               int endIndex = fileContents.indexOf('\n', index);
+                               logger.info
+                                 ("RepositoryAudit: Attempted download: '{}'", fileContents.substring(index, endIndex));
+                               index = endIndex;
+                         }
+                       else if (fileContents.regionMatches(index, "loaded: ", 0, 8))
+                         {
+                               index += 8;
+                               int endIndex = fileContents.indexOf(' ', index);
+                               logger.info
+                                 ("RepositoryAudit: Successful download: '{}'",fileContents.substring(index, endIndex));
+                               index = endIndex;
+                         }
+                 }
+         }
+
+       /*
+        * 5) Check the contents of the directory to make sure the downloads
+        *    were successful
+        */
+       for (Artifact artifact : artifacts)
+         {
+               if (repo.resolve(artifact.groupId.replace('.','/'))
+                       .resolve(artifact.artifactId)
+                       .resolve(artifact.version)
+                       .resolve(artifact.artifactId + "-" + artifact.version + "."
+                                        + artifact.type).toFile().exists())
+                 {
+                       // artifact exists, as expected
+                       logger.info("RepositoryAudit: {} : exists", artifact.toString());
+                 }
+               else
+                 {
+                       // Audit ERROR: artifact download failed for some reason
+                       logger.error("RepositoryAudit: {}: does not exist", artifact.toString());
+                       if (!ignoreErrors)
+                         {
+                               response.append("Failed to download artifact: ")
+                                 .append(artifact).append('\n');
+                               setResponse(response.toString());
+                         }
+                 }
+         }
+
+       /*
+        * 6) Use 'curl' to delete the uploaded test file
+        *    (only if repository information is specified)
+        */
+       if (upload)
+         {
+               if (runProcess
+                       (timeoutInSeconds, dir.toFile(), null,
+                        "curl",
+                        "--request", "DELETE",
+                        "--user", repositoryUsername + ":" + repositoryPassword,
+                        (repositoryUrl + "/" + groupId.replace('.', '/') + "/" +
+                         artifactId + "/" + version))
+                       != 0)
+                 {
+                       logger.error
+                         ("RepositoryAudit: delete of uploaded artifact failed");
+                       if (!ignoreErrors)
+                         {
+                               response.append("delete of uploaded artifact failed\n");
+                               setResponse(response.toString());
+                         }
+                 }
+               else
+                 {
+                       logger.info
+                         ("RepositoryAudit: delete of uploaded artifact succeeded");
+                       artifacts.add(new Artifact(groupId, artifactId, version, "txt"));
+                 }
+         }
+
+       /*
+        * 7) Remove the temporary directory
+        */
+       Files.walkFileTree
+         (dir,
+          new SimpleFileVisitor<Path>()
+          {
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                  {
+                        // logger.info("RepositoryAudit: Delete " + file);
+                        file.toFile().delete();
+                        return(FileVisitResult.CONTINUE);
+                  }
+
+                public FileVisitResult postVisitDirectory(Path file, IOException e)
+                  throws IOException
+                  {
+                        if (e == null)
+                          {
+                                // logger.info("RepositoryAudit: Delete " + file);
+                                file.toFile().delete();
+                                return(FileVisitResult.CONTINUE);
+                          }
+                        else
+                          {
+                                throw(e);
+                          }
+                  }
+          });
+  }
+
+  /**
+   * Run a process, and wait for the response
+   *
+   * @param timeoutInSeconds the number of seconds to wait for the
+   *   process to terminate
+   * @param directory the execution directory of the process
+   *   (null = current directory)
+   * @param stdout the file to contain the standard output
+   *   (null = discard standard output)
+   * @param command command and arguments
+   * @return the return value of the process
+   * @throws IOException, InterruptedException
+   */
+  static int runProcess(long timeoutInSeconds,
+                                               File directory, File stdout, String... command)
+       throws IOException, InterruptedException
+  {
+       ProcessBuilder pb = new ProcessBuilder(command);
+       if (directory != null)
+         {
+               pb.directory(directory);
+         }
+       if (stdout != null)
+         {
+               pb.redirectOutput(stdout);
+         }
+
+       Process process = pb.start();
+       if (process.waitFor(timeoutInSeconds, TimeUnit.SECONDS))
+         {
+               // process terminated before the timeout
+               return(process.exitValue());
+         }
+       
+       // process timed out -- kill it, and return -1
+       process.destroyForcibly();
+       return(-1);
+  }
+
+  /* ============================================================ */
+
+  /**
+   * An instance of this class exists for each artifact that we are trying
+   * to download.
+   */
+  static class Artifact
+  {
+       String groupId, artifactId, version, type;
+
+       /**
+        * Constructor - populate the 'Artifact' instance
+        *
+        * @param groupId groupId of artifact
+        * @param artifactId artifactId of artifact
+        * @param version version of artifact
+        * @param type type of the artifact (e.g. "jar")
+        */
+       Artifact(String groupId, String artifactId, String version, String type)
+       {
+         this.groupId = groupId;
+         this.artifactId = artifactId;
+         this.version = version;
+         this.type = type;
+       }
+
+       /**
+        * Constructor - populate an 'Artifact' instance
+        *
+        * @param artifact a string of the form:
+        *              "<groupId>/<artifactId>/<version>[/<type>]"
+        * @throws IllegalArgumentException if 'artifact' has the incorrect format
+        */
+       Artifact(String artifact)
+       {
+         String[] segments = artifact.split("/");
+         if (segments.length != 4 && segments.length != 3)
+               {
+                 throw(new IllegalArgumentException("groupId/artifactId/version/type"));
+               }
+         groupId = segments[0];
+         artifactId = segments[1];
+         version = segments[2];
+         type = (segments.length == 4 ? segments[3] : "jar");
+       }
+
+       /**
+        * @return the artifact id in the form:
+        *              "<groupId>/<artifactId>/<version>/<type>"
+        */
+       public String toString()
+       {
+         return(groupId + "/" + artifactId + "/" + version + "/" + type);
+       }
+  }
+}
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeature.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementFeature.java
new file mode 100644 (file)
index 0000000..6d47039
--- /dev/null
@@ -0,0 +1,275 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.io.IOException;
+import java.util.Observer;
+import java.util.Properties;
+
+import org.onap.policy.drools.statemanagement.StateManagementFeatureAPI;
+import org.onap.policy.common.im.StandbyStatusException;
+import org.onap.policy.common.im.StateManagement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.onap.policy.drools.core.PolicySessionFeatureAPI;
+import org.onap.policy.drools.features.PolicyEngineFeatureAPI;
+import org.onap.policy.drools.utils.PropertyUtil;
+
+/**
+ * If this feature is supported, there is a single instance of it.
+ * It adds persistence to Drools sessions, but it is also intertwined with
+ * active/standby state management and IntegrityMonitor. For now, they are
+ * all treated as a single feature, but it would be nice to separate them.
+ *
+ * The bulk of the code here was once in other classes, such as
+ * 'PolicyContainer' and 'Main'. It was moved here as part of making this
+ * a separate optional feature.
+ */
+
+public class StateManagementFeature implements StateManagementFeatureAPI, 
+                               PolicySessionFeatureAPI, PolicyEngineFeatureAPI
+{
+       // get an instance of logger
+       private static final Logger logger =
+                       LoggerFactory.getLogger(StateManagementFeature.class);
+       
+       private DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = null;
+       private StateManagement stateManagement = null;
+
+       /**************************/
+       /* 'FeatureAPI' interface */
+       /**************************/
+
+       public StateManagementFeature(){
+               if(logger.isDebugEnabled()){
+                       logger.debug("StateManagementFeature() constructor");
+               }
+       }
+       
+       @Override
+       public void globalInit(String args[], String configDir)
+       {
+               // Initialization code associated with 'PolicyContainer'
+               if(logger.isDebugEnabled()){
+                       logger.debug("StateManagementFeature.globalInit({}) entry", configDir);
+               }
+
+               try
+               {
+                       droolsPdpIntegrityMonitor = DroolsPDPIntegrityMonitor.init(configDir);
+               }
+               catch (Exception e)
+               {
+                       if(logger.isDebugEnabled()){
+                               logger.debug("DroolsPDPIntegrityMonitor initialization exception: ", e);
+                       }
+                       logger.error("DroolsPDPIntegrityMonitor.init()", e);
+               }
+
+               initializeProperties(configDir);
+
+               //At this point the DroolsPDPIntegrityMonitor instance must exist. Let's check it.
+               try {
+                       droolsPdpIntegrityMonitor = DroolsPDPIntegrityMonitor.getInstance();
+                       stateManagement = droolsPdpIntegrityMonitor.getStateManager();
+                       if(logger.isDebugEnabled()){
+                               logger.debug("StateManagementFeature.globalInit(): "
+                                       + "stateManagement.getAdminState(): {}", stateManagement.getAdminState());
+                       }
+                       if(stateManagement == null){
+                               if(logger.isDebugEnabled()){
+                                       logger.debug("StateManagementFeature.globalInit(): stateManagement is NULL!");
+                               }
+                       }
+               } catch (Exception e1) {
+                       String msg = "  \n";
+                       if(logger.isDebugEnabled()){
+                               logger.debug("StateManagementFeature.globalInit(): DroolsPDPIntegrityMonitor"
+                                       + " initialization failed with exception:", e1);
+                       }
+                       logger.error("DroolsPDPIntegrityMonitor.init(): StateManagementFeature startup failed "
+                                       + "to get DroolsPDPIntegrityMonitor instance:", e1);
+                       e1.printStackTrace();
+               }
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void addObserver(Observer stateChangeObserver) {
+               if(logger.isDebugEnabled()){
+                       logger.debug("StateManagementFeature.addObserver() entry\n"
+                                       + "StateManagementFeature.addObserver(): "
+                                       + "stateManagement.getAdminState(): {}", stateManagement.getAdminState());
+               }
+               stateManagement.addObserver(stateChangeObserver);
+               if(logger.isDebugEnabled()){
+                       logger.debug("StateManagementFeature.addObserver() exit");
+               }
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getAdminState() {
+               return stateManagement.getAdminState();
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getOpState() {
+               return stateManagement.getOpState();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getAvailStatus() {
+               return stateManagement.getAvailStatus();
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getStandbyStatus() {
+               return stateManagement.getStandbyStatus();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getStandbyStatus(String resourceName) {
+               return stateManagement.getStandbyStatus(resourceName);
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void disableFailed(String resourceName) throws Exception {
+               stateManagement.disableFailed(resourceName);
+
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void disableFailed() throws Exception {
+               stateManagement.disableFailed();
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void promote() throws StandbyStatusException, Exception {
+               stateManagement.promote();              
+       }
+
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public void demote() throws Exception {
+               stateManagement.demote();
+       }
+       
+       /**
+        * {@inheritDoc}
+        */
+       @Override
+       public String getResourceName() {
+               return StateManagementProperties.getProperty(StateManagementProperties.NODE_NAME);
+       }
+       
+       /**
+        * {@inheritDoc}
+        * @return 
+        */
+       @Override
+       public boolean lock(){
+               try{
+                       stateManagement.lock();
+               }catch(Exception e){
+                       logger.error("StateManagementFeature.lock() failed with exception: {}", e);
+                       return false;
+               }
+               return true;
+       }
+       
+       /**
+        * {@inheritDoc}
+        * @throws Exception 
+        */
+       @Override
+       public boolean unlock(){
+               try{
+                       stateManagement.unlock();
+               }catch(Exception e){
+                       logger.error("StateManagementFeature.unlock() failed with exception: {}", e);
+                       return false;
+               }
+               return true;
+       }
+       
+       /**
+        * {@inheritDoc}
+        * @throws Exception 
+        */
+       @Override
+       public boolean isLocked(){
+               String admin = stateManagement.getAdminState();
+               if(admin.equals(StateManagement.LOCKED)){
+                       return true;
+               }else{
+                       return false;
+               }
+       }
+       
+       @Override
+       public int getSequenceNumber() {
+               return SEQ_NUM;
+       }
+
+       /**
+        * Read in the properties and initialize the StateManagementProperties.
+        */
+       private static void initializeProperties(String configDir)
+       {
+               //Get the state management properties 
+               try {
+                       Properties pIm =
+                                       PropertyUtil.getProperties(configDir + "/feature-state-management.properties");
+                       StateManagementProperties.initProperties(pIm);
+                       logger.info("initializeProperties: resourceName= {}", StateManagementProperties.getProperty(StateManagementProperties.NODE_NAME));
+               } catch (IOException e1) {
+                       logger.error("initializeProperties", e1);
+               }
+       }
+}
diff --git a/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementProperties.java b/feature-state-management/src/main/java/org/onap/policy/drools/statemanagement/StateManagementProperties.java
new file mode 100644 (file)
index 0000000..c8e17ea
--- /dev/null
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * feature-state-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class StateManagementProperties {
+       // get an instance of logger 
+       private static final Logger  logger = LoggerFactory.getLogger(StateManagementProperties.class);
+               
+       public static final String NODE_NAME = "resource.name";
+       public static final String SITE_NAME = "site_name";
+       
+       public static final String DB_DRIVER = "javax.persistence.jdbc.driver";
+       public static final String DB_URL = "javax.persistence.jdbc.url";
+       public static final String DB_USER = "javax.persistence.jdbc.user";
+       public static final String DB_PWD = "javax.persistence.jdbc.password";
+       
+       private static Properties properties = null;
+       /*
+        * Initialize the parameter values from the feature-state-management.properties file values
+        * 
+        * This is designed so that the Properties object is obtained from the feature-state-management.properties
+        * file and then is passed to this method to initialize the value of the parameters.
+        * This allows the flexibility of JUnit tests using getProperties(filename) to get the
+        * properties while runtime methods can use getPropertiesFromClassPath(filename).
+        * 
+        */
+       public static void initProperties (Properties prop){
+               logger.info("StateManagementProperties.initProperties(Properties): entry");
+               logger.info("\n\nStateManagementProperties.initProperties: Properties = \n{}\n\n", prop);
+               
+               properties = prop;
+       }
+
+       public static String getProperty(String key){
+               return properties.getProperty(key);
+       }
+       
+       public static Properties getProperties() {
+               return properties;
+       }
+}
diff --git a/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.core.PolicySessionFeatureAPI b/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.core.PolicySessionFeatureAPI
new file mode 100644 (file)
index 0000000..9ffef57
--- /dev/null
@@ -0,0 +1 @@
+org.onap.policy.drools.statemanagement.StateManagementFeature
\ No newline at end of file
diff --git a/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureAPI b/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.features.PolicyEngineFeatureAPI
new file mode 100644 (file)
index 0000000..74d0b99
--- /dev/null
@@ -0,0 +1 @@
+org.onap.policy.drools.statemanagement.StateManagementFeature
diff --git a/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.statemanagement.StateManagementFeatureAPI b/feature-state-management/src/main/resources/META-INF/services/org.onap.policy.drools.statemanagement.StateManagementFeatureAPI
new file mode 100644 (file)
index 0000000..74d0b99
--- /dev/null
@@ -0,0 +1 @@
+org.onap.policy.drools.statemanagement.StateManagementFeature
diff --git a/feature-state-management/src/test/java/org/onap/policy/drools/statemanagement/test/StateManagementTest.java b/feature-state-management/src/test/java/org/onap/policy/drools/statemanagement/test/StateManagementTest.java
new file mode 100644 (file)
index 0000000..e458dce
--- /dev/null
@@ -0,0 +1,245 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-persistence
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.drools.statemanagement.test;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Properties;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.EntityTransaction;
+import javax.persistence.Persistence;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.onap.policy.common.im.StateManagement;
+import org.onap.policy.drools.core.PolicySessionFeatureAPI;
+import org.onap.policy.drools.statemanagement.StateManagementFeatureAPI;
+import org.onap.policy.drools.statemanagement.StateManagementProperties;
+
+public class StateManagementTest {
+               
+       // get an instance of logger 
+       private static Logger  logger = LoggerFactory.getLogger(StateManagementTest.class);     
+       
+       /*
+        * Sleep 5 seconds after each test to allow interrupt (shutdown) recovery.
+        */
+        
+       private long interruptRecoveryTime = 1000;
+       
+       StateManagementFeatureAPI stateManagementFeature;
+       
+       /*
+        * All you need to do here is create an instance of StateManagementFeature class.  Then,
+        * check it initial state and the state after diableFailed() and promote()
+        */
+       
+       @BeforeClass
+       public static void setUpClass() throws Exception {
+               
+               logger.info("setUpClass: Entering");
+
+               String userDir = System.getProperty("user.dir");
+               logger.debug("setUpClass: userDir=" + userDir);
+               System.setProperty("com.sun.management.jmxremote.port", "9980");
+               System.setProperty("com.sun.management.jmxremote.authenticate","false");
+                               
+               initializeDb();
+               
+               logger.info("setUpClass: Exiting");
+       }
+
+       @AfterClass
+       public static void tearDownClass() throws Exception {
+                               
+       }
+
+       @Before
+       public void setUp() throws Exception {
+               
+       }
+
+       @After
+       public void tearDown() throws Exception {
+               
+       }
+
+       
+       /*
+        * Verifies that StateManagementFeature starts and runs successfully.
+        */
+        
+       //@Ignore
+       @Test
+       public void testStateManagementOperation() throws Exception {
+               
+               logger.debug("\n\ntestStateManagementOperation: Entering\n\n");
+
+               logger.debug("testStateManagementOperation: Reading StateManagementProperties");
+
+               String configDir = "src/test/resources";
+               
+               Properties fsmProperties = new Properties();
+               fsmProperties.load(new FileInputStream(new File(
+                               configDir + "/feature-state-management.properties")));
+               String thisPdpId = fsmProperties
+                               .getProperty(StateManagementProperties.NODE_NAME);
+
+               StateManagementFeatureAPI stateManagementFeature = null;
+               for (StateManagementFeatureAPI feature : StateManagementFeatureAPI.impl.getList())
+               {
+                       ((PolicySessionFeatureAPI) feature).globalInit(null, configDir);
+                       stateManagementFeature = feature;
+                       logger.debug("testStateManagementOperation stateManagementFeature.getResourceName(): " + stateManagementFeature.getResourceName());
+                       break;
+               }
+               if(stateManagementFeature == null){
+                       String msg = "testStateManagementOperation failed to initialize.  "
+                                       + "Unable to get instance of StateManagementFeatureAPI "
+                                       + "with resourceID: " + thisPdpId;
+                       logger.error(msg);
+                       logger.debug(msg);
+               }
+               
+               Thread.sleep(interruptRecoveryTime);
+               
+               String admin = stateManagementFeature.getAdminState();
+               String oper = stateManagementFeature.getOpState();
+               String avail = stateManagementFeature.getAvailStatus();
+               String standby = stateManagementFeature.getStandbyStatus();
+               
+               logger.debug("admin = {}", admin);
+               System.out.println("admin = " + admin);
+               logger.debug("oper = {}", oper);
+               System.out.println("oper = " + oper);
+               logger.debug("avail = {}", avail);
+               System.out.println("avail = " + avail);
+               logger.debug("standby = {}", standby);
+               System.out.println("standby = " + standby);
+               
+               assertTrue("Admin state not unlocked after initialization", admin.equals(StateManagement.UNLOCKED));
+               assertTrue("Operational state not enabled after initialization", oper.equals(StateManagement.ENABLED));
+               
+               try{
+                       stateManagementFeature.disableFailed();
+               }catch(Exception e){
+                       logger.error(e.getMessage());
+                       System.out.println(e.getMessage());
+                       assertTrue(e.getMessage(), false);
+               }
+               
+               Thread.sleep(interruptRecoveryTime);
+               
+               admin = stateManagementFeature.getAdminState();
+               oper = stateManagementFeature.getOpState();
+               avail = stateManagementFeature.getAvailStatus();
+               standby = stateManagementFeature.getStandbyStatus();
+               
+               logger.debug("after disableFailed()");
+               System.out.println("after disableFailed()");
+               logger.debug("admin = {}", admin);
+               System.out.println("admin = " + admin);
+               logger.debug("oper = {}", oper);
+               System.out.println("oper = " + oper);
+               logger.debug("avail = {}", avail);
+               System.out.println("avail = " + avail);
+               logger.debug("standby = {}", standby);
+               System.out.println("standby = " + standby);
+               
+               assertTrue("Operational state not disabled after disableFailed()", oper.equals(StateManagement.DISABLED));
+               assertTrue("Availability status not failed after disableFailed()", avail.equals(StateManagement.FAILED));
+               
+               
+               try{
+                       stateManagementFeature.promote();
+               }catch(Exception e){
+                       logger.debug(e.getMessage());
+                       System.out.println(e.getMessage());
+               }
+               
+               Thread.sleep(interruptRecoveryTime);
+               
+               admin = stateManagementFeature.getAdminState();
+               oper = stateManagementFeature.getOpState();
+               avail = stateManagementFeature.getAvailStatus();
+               standby = stateManagementFeature.getStandbyStatus();
+               
+               logger.debug("after promote()");
+               System.out.println("after promote()");
+               logger.debug("admin = {}", admin);
+               System.out.println("admin = " + admin);
+               logger.debug("oper = {}", oper);
+               System.out.println("oper = " + oper);
+               logger.debug("avail = {}", avail);
+               System.out.println("avail = " + avail);
+               logger.debug("standby = {}", standby);
+               System.out.println("standby = " + standby);
+
+               assertTrue("Standby status not coldstandby after promote()", standby.equals(StateManagement.COLD_STANDBY));
+                               
+               logger.debug("\n\ntestStateManagementOperation: Exiting\n\n");
+       }       
+       
+    /*
+     * This method initializes and cleans the DB so that PDP-D will be able to 
+     * store fresh records in the DB.
+     */
+     
+       public static void initializeDb(){
+               
+               logger.debug("initializeDb: Entering");
+               
+       Properties cleanProperties = new Properties();
+       cleanProperties.put(StateManagementProperties.DB_DRIVER,"org.h2.Driver");
+       cleanProperties.put(StateManagementProperties.DB_URL, "jdbc:h2:file:./sql/statemanagement");
+       cleanProperties.put(StateManagementProperties.DB_USER, "sa");
+       cleanProperties.put(StateManagementProperties.DB_PWD, "");
+
+       EntityManagerFactory emf = Persistence.createEntityManagerFactory("junitPU", cleanProperties);
+               
+               EntityManager em = emf.createEntityManager();
+               // Start a transaction
+               EntityTransaction et = em.getTransaction();
+
+               et.begin();
+
+               // Clean up the DB
+               em.createQuery("Delete from StateManagementEntity").executeUpdate();
+               em.createQuery("Delete from ForwardProgressEntity").executeUpdate();
+               em.createQuery("Delete from ResourceRegistrationEntity").executeUpdate();
+
+               // commit transaction
+               et.commit();
+               em.close();
+               
+               logger.debug("initializeDb: Exiting");
+       }       
+}
diff --git a/feature-state-management/src/test/resources/META-INF/persistence.xml b/feature-state-management/src/test/resources/META-INF/persistence.xml
new file mode 100644 (file)
index 0000000..d26ab44
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ============LICENSE_START=======================================================
+  feature-state-management
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<persistence version="2.1"
+       xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
+
+       <persistence-unit name="junitPU" transaction-type="RESOURCE_LOCAL">
+               <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
+               <class>org.onap.policy.common.im.jpa.StateManagementEntity</class>
+               <class>org.onap.policy.common.im.jpa.ForwardProgressEntity</class>
+               <class>org.onap.policy.common.im.jpa.ResourceRegistrationEntity</class>
+               <properties>
+                       <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/>
+                       <property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/> 
+            <property name="javax.persistence.schema-generation.scripts.create-target" value="./sql/generatedCreateStateManagement.ddl"/>
+            <property name="javax.persistence.schema-generation.scripts.drop-target" value="./sql/generatedDropStateManagement.ddl"/>
+        </properties>
+       </persistence-unit>
+
+</persistence>
diff --git a/feature-state-management/src/test/resources/feature-state-management.properties b/feature-state-management/src/test/resources/feature-state-management.properties
new file mode 100644 (file)
index 0000000..7b4a697
--- /dev/null
@@ -0,0 +1,74 @@
+###
+# ============LICENSE_START=======================================================
+# feature-state-management
+# ================================================================================
+# Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+# 
+#      http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+###
+
+# DB properties
+javax.persistence.jdbc.driver = org.h2.Driver
+javax.persistence.jdbc.url  = jdbc:h2:file:./sql/statemanagement
+javax.persistence.jdbc.user = sa
+javax.persistence.jdbc.password =
+
+# DroolsPDPIntegrityMonitor Properties
+hostPort = 0.0.0.0:57692
+
+#IntegrityMonitor Properties
+
+# Must be unique across the system
+resource.name=pdp1
+# Name of the site in which this node is hosted 
+site_name = pdp_1
+# Forward Progress Monitor update interval seconds
+fp_monitor_interval = 30
+# Failed counter threshold before failover 
+failed_counter_threshold = 3
+# Interval between test transactions when no traffic seconds
+test_trans_interval = 10
+# Interval between writes of the FPC to the DB seconds 
+write_fpc_interval = 5
+# Node type Note: Make sure you don't leave any trailing spaces, or you'll get an 'invalid node type' error! 
+node_type = pdp_drools
+# Dependency groups are groups of resources upon which a node operational state is dependent upon. 
+# Each group is a comma-separated list of resource names and groups are separated by a semicolon.  For example:
+# dependency_groups=site_1.astra_1,site_1.astra_2;site_1.brms_1,site_1.brms_2;site_1.logparser_1;site_1.pypdp_1
+dependency_groups=
+# When set to true, dependent health checks are performed by using JMX to invoke test() on the dependent.
+# The default false is to use state checks for health.
+test_via_jmx=true
+# This is the max number of seconds beyond which a non incrementing FPC is considered a failure
+max_fpc_update_interval=120
+# Run the state audit every 60 seconds (60000 ms).  The state audit finds stale DB entries in the 
+# forwardprogressentity table and marks the node as disabled/failed in the statemanagemententity 
+# table. NOTE! It will only run on nodes that have a standbystatus = providingservice.
+# A value of <= 0 will turn off the state audit.
+state_audit_interval_ms=60000
+# The refresh state audit is run every (default) 10 minutes (600000 ms) to clean up any state corruption in the 
+# DB statemanagemententity table. It only refreshes the DB state entry for the local node.  That is, it does not
+# refresh the state of any other nodes.  A value <= 0 will turn the audit off. Any other value will override 
+# the default of 600000 ms.
+refresh_state_audit_interval_ms=600000
+
+
+# Repository audit properties
+# Flag to control the execution of the subsystemTest for the Nexus Maven repository
+repository.audit.is.active=false
+repository.audit.ignore.errors=true
+
+# DB Audit Properties
+# Flag to control the execution of the subsystemTest for the Database
+db.audit.is.active=false
diff --git a/feature-state-management/src/test/resources/logback-test.xml b/feature-state-management/src/test/resources/logback-test.xml
new file mode 100644 (file)
index 0000000..58cabf9
--- /dev/null
@@ -0,0 +1,47 @@
+<!--
+  ============LICENSE_START=======================================================
+  feature-state-management
+  ================================================================================
+  Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+  ================================================================================
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ============LICENSE_END=========================================================
+  -->
+
+<!-- Controls the output of logs for JUnit tests -->
+
+<configuration>
+
+       <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+               <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+                       <Pattern>
+                               %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n
+                       </Pattern>
+               </encoder>
+       </appender>
+       <appender name="FILE" class="ch.qos.logback.core.FileAppender">
+               <file>logs/debug.log</file>
+               <encoder>
+                       <Pattern>
+                               %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36}.%M\(%line\) - %msg%n
+                       </Pattern>
+               </encoder>
+       </appender>
+       
+       <root level="debug">
+               <appender-ref ref="STDOUT" />
+               <appender-ref ref="FILE" />
+       </root>
+
+</configuration>
+
index 2b3a136..7a765c3 100644 (file)
                        <version>${project.version}</version>
                        <type>zip</type>
                </dependency>
+               <dependency>
+                       <groupId>org.onap.policy.drools-pdp</groupId>
+                       <artifactId>feature-state-management</artifactId>
+                       <version>${project.version}</version>
+                       <type>zip</type>
+               </dependency>
        </dependencies>
 
 </project>
diff --git a/pom.xml b/pom.xml
index 75c2748..35aca8e 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -73,6 +73,8 @@
                <module>feature-eelf</module>
                <module>feature-session-persistence</module>
                <module>feature-test-transaction</module>
+               <module>api-state-management</module>
+               <module>feature-state-management</module>
                <module>packages</module>
        </modules>