Update zookeeper and libthrift (#1081)

* Update zookeeper and libthrift dependencies to avoid using
  dependencies with known outstanding vulnerabilities
* Add script and build profile to automatically (re-)build thrift files
  during the Maven build
diff --git a/modules/core/pom.xml b/modules/core/pom.xml
index 8f38f5a..5ed4406 100644
--- a/modules/core/pom.xml
+++ b/modules/core/pom.xml
@@ -72,7 +72,6 @@
     <dependency>
       <groupId>org.apache.thrift</groupId>
       <artifactId>libthrift</artifactId>
-      <version>0.11.0</version>
       <optional>true</optional>
     </dependency>
     <dependency>
@@ -167,4 +166,29 @@
       </plugin>
     </plugins>
   </build>
+  <profiles>
+    <profile>
+      <id>thrift</id>
+      <build>
+        <plugins>
+          <plugin>
+            <groupId>org.codehaus.mojo</groupId>
+            <artifactId>exec-maven-plugin</artifactId>
+            <executions>
+              <execution>
+                <id>generate-thrift</id>
+                <goals>
+                  <goal>exec</goal>
+                </goals>
+                <phase>generate-sources</phase>
+                <configuration>
+                  <executable>${basedir}/src/main/scripts/generate-thrift.sh</executable>
+                </configuration>
+              </execution>
+            </executions>
+          </plugin>
+        </plugins>
+      </build>
+    </profile>
+  </profiles>
 </project>
diff --git a/modules/core/src/main/java/org/apache/fluo/core/thrift/OracleService.java b/modules/core/src/main/java/org/apache/fluo/core/thrift/OracleService.java
index bce6ffb..a0149c4 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/thrift/OracleService.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/thrift/OracleService.java
@@ -1,5 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
 /**
- * Autogenerated by Thrift Compiler (0.11.0)
+ * Autogenerated by Thrift Compiler (0.12.0)
  *
  * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
  *  @generated
@@ -253,7 +269,7 @@
       }
 
       @Override
-      protected boolean handleRuntimeExceptions() {
+      protected boolean rethrowUnhandledExceptions() {
         return false;
       }
 
@@ -280,7 +296,7 @@
       }
 
       @Override
-      protected boolean handleRuntimeExceptions() {
+      protected boolean rethrowUnhandledExceptions() {
         return false;
       }
 
@@ -474,7 +490,7 @@
     private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY =
         new getTimestamps_argsTupleSchemeFactory();
 
-    public java.lang.String id; // required
+    public @org.apache.thrift.annotation.Nullable java.lang.String id; // required
     public int num; // required
 
     /**
@@ -496,6 +512,7 @@
       /**
        * Find the _Fields constant that matches fieldId, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByThriftId(int fieldId) {
         switch (fieldId) {
           case 1: // ID
@@ -520,6 +537,7 @@
       /**
        * Find the _Fields constant that matches name, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByName(java.lang.String name) {
         return byName.get(name);
       }
@@ -594,11 +612,12 @@
       this.num = 0;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public java.lang.String getId() {
       return this.id;
     }
 
-    public getTimestamps_args setId(java.lang.String id) {
+    public getTimestamps_args setId(@org.apache.thrift.annotation.Nullable java.lang.String id) {
       this.id = id;
       return this;
     }
@@ -642,7 +661,8 @@
           org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __NUM_ISSET_ID, value);
     }
 
-    public void setFieldValue(_Fields field, java.lang.Object value) {
+    public void setFieldValue(_Fields field,
+        @org.apache.thrift.annotation.Nullable java.lang.Object value) {
       switch (field) {
         case ID:
           if (value == null) {
@@ -663,6 +683,7 @@
       }
     }
 
+    @org.apache.thrift.annotation.Nullable
     public java.lang.Object getFieldValue(_Fields field) {
       switch (field) {
         case ID:
@@ -773,6 +794,7 @@
       return 0;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public _Fields fieldForId(int fieldId) {
       return _Fields.findByThriftId(fieldId);
     }
@@ -973,7 +995,7 @@
     private static final org.apache.thrift.scheme.SchemeFactory TUPLE_SCHEME_FACTORY =
         new getTimestamps_resultTupleSchemeFactory();
 
-    public Stamps success; // required
+    public @org.apache.thrift.annotation.Nullable Stamps success; // required
 
     /**
      * The set of fields this struct contains, along with convenience methods for finding and
@@ -994,6 +1016,7 @@
       /**
        * Find the _Fields constant that matches fieldId, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByThriftId(int fieldId) {
         switch (fieldId) {
           case 0: // SUCCESS
@@ -1016,6 +1039,7 @@
       /**
        * Find the _Fields constant that matches name, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByName(java.lang.String name) {
         return byName.get(name);
       }
@@ -1077,11 +1101,12 @@
       this.success = null;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public Stamps getSuccess() {
       return this.success;
     }
 
-    public getTimestamps_result setSuccess(Stamps success) {
+    public getTimestamps_result setSuccess(@org.apache.thrift.annotation.Nullable Stamps success) {
       this.success = success;
       return this;
     }
@@ -1101,7 +1126,8 @@
       }
     }
 
-    public void setFieldValue(_Fields field, java.lang.Object value) {
+    public void setFieldValue(_Fields field,
+        @org.apache.thrift.annotation.Nullable java.lang.Object value) {
       switch (field) {
         case SUCCESS:
           if (value == null) {
@@ -1114,6 +1140,7 @@
       }
     }
 
+    @org.apache.thrift.annotation.Nullable
     public java.lang.Object getFieldValue(_Fields field) {
       switch (field) {
         case SUCCESS:
@@ -1198,6 +1225,7 @@
       return 0;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public _Fields fieldForId(int fieldId) {
       return _Fields.findByThriftId(fieldId);
     }
@@ -1391,6 +1419,7 @@
       /**
        * Find the _Fields constant that matches fieldId, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByThriftId(int fieldId) {
         switch (fieldId) {
           default:
@@ -1411,6 +1440,7 @@
       /**
        * Find the _Fields constant that matches name, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByName(java.lang.String name) {
         return byName.get(name);
       }
@@ -1455,11 +1485,13 @@
     @Override
     public void clear() {}
 
-    public void setFieldValue(_Fields field, java.lang.Object value) {
+    public void setFieldValue(_Fields field,
+        @org.apache.thrift.annotation.Nullable java.lang.Object value) {
       switch (field) {
       }
     }
 
+    @org.apache.thrift.annotation.Nullable
     public java.lang.Object getFieldValue(_Fields field) {
       switch (field) {
       }
@@ -1516,6 +1548,7 @@
       return 0;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public _Fields fieldForId(int fieldId) {
       return _Fields.findByThriftId(fieldId);
     }
@@ -1675,6 +1708,7 @@
       /**
        * Find the _Fields constant that matches fieldId, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByThriftId(int fieldId) {
         switch (fieldId) {
           case 0: // SUCCESS
@@ -1697,6 +1731,7 @@
       /**
        * Find the _Fields constant that matches name, or null if its not found.
        */
+      @org.apache.thrift.annotation.Nullable
       public static _Fields findByName(java.lang.String name) {
         return byName.get(name);
       }
@@ -1786,7 +1821,8 @@
           org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __SUCCESS_ISSET_ID, value);
     }
 
-    public void setFieldValue(_Fields field, java.lang.Object value) {
+    public void setFieldValue(_Fields field,
+        @org.apache.thrift.annotation.Nullable java.lang.Object value) {
       switch (field) {
         case SUCCESS:
           if (value == null) {
@@ -1799,6 +1835,7 @@
       }
     }
 
+    @org.apache.thrift.annotation.Nullable
     public java.lang.Object getFieldValue(_Fields field) {
       switch (field) {
         case SUCCESS:
@@ -1881,6 +1918,7 @@
       return 0;
     }
 
+    @org.apache.thrift.annotation.Nullable
     public _Fields fieldForId(int fieldId) {
       return _Fields.findByThriftId(fieldId);
     }
diff --git a/modules/core/src/main/java/org/apache/fluo/core/thrift/Stamps.java b/modules/core/src/main/java/org/apache/fluo/core/thrift/Stamps.java
index 6281964..852dac9 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/thrift/Stamps.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/thrift/Stamps.java
@@ -1,5 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
 /**
- * Autogenerated by Thrift Compiler (0.11.0)
+ * Autogenerated by Thrift Compiler (0.12.0)
  *
  * DO NOT EDIT UNLESS YOU ARE SURE THAT YOU KNOW WHAT YOU ARE DOING
  *  @generated
@@ -46,6 +62,7 @@
     /**
      * Find the _Fields constant that matches fieldId, or null if its not found.
      */
+    @org.apache.thrift.annotation.Nullable
     public static _Fields findByThriftId(int fieldId) {
       switch (fieldId) {
         case 1: // TX_STAMPS_START
@@ -70,6 +87,7 @@
     /**
      * Find the _Fields constant that matches name, or null if its not found.
      */
+    @org.apache.thrift.annotation.Nullable
     public static _Fields findByName(java.lang.String name) {
       return byName.get(name);
     }
@@ -190,7 +208,8 @@
         org.apache.thrift.EncodingUtils.setBit(__isset_bitfield, __GCSTAMP_ISSET_ID, value);
   }
 
-  public void setFieldValue(_Fields field, java.lang.Object value) {
+  public void setFieldValue(_Fields field,
+      @org.apache.thrift.annotation.Nullable java.lang.Object value) {
     switch (field) {
       case TX_STAMPS_START:
         if (value == null) {
@@ -211,6 +230,7 @@
     }
   }
 
+  @org.apache.thrift.annotation.Nullable
   public java.lang.Object getFieldValue(_Fields field) {
     switch (field) {
       case TX_STAMPS_START:
@@ -321,6 +341,7 @@
     return 0;
   }
 
+  @org.apache.thrift.annotation.Nullable
   public _Fields fieldForId(int fieldId) {
     return _Fields.findByThriftId(fieldId);
   }
@@ -495,3 +516,4 @@
         : TUPLE_SCHEME_FACTORY).getScheme();
   }
 }
+
diff --git a/modules/core/src/main/scripts/generate-thrift.sh b/modules/core/src/main/scripts/generate-thrift.sh
new file mode 100755
index 0000000..7089d3d
--- /dev/null
+++ b/modules/core/src/main/scripts/generate-thrift.sh
@@ -0,0 +1,132 @@
+#! /usr/bin/env bash
+
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+# This script will regenerate the thrift code for Fluo's RPC mechanisms.
+
+fail() {
+  echo "$@"
+  exit 1
+}
+
+attachLicense() {
+  # concatenate the below license with the input file, $1, then overwrite it
+  cat - "$1" > "$1-tmp" <<EOF
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+EOF
+  [[ $? -eq 0 ]] || fail unable to attach license
+  mv -f "$1-tmp" "$1" || fail unable to replace file after attaching license
+}
+
+getThriftVersionFromPom() {
+  local returnCodes
+  xmllint --shell "../../pom.xml" \
+    <<<'xpath /*[local-name()="project"]/*[local-name()="properties"]/*[local-name()="thrift.version"]/text()' \
+    | grep content= \
+    | cut -f2 -d=
+  returnCodes=( "${PIPESTATUS[@]}" )
+  for x in "${returnCodes[@]}"; do
+    [[ $x -eq 0 ]] || return $x
+  done
+}
+
+requireThriftVersion() {
+  # test to see if thrift is installed; $1 is the expected version
+  local ver
+  ver=$(thrift -version 2>/dev/null | grep -cF "$1")
+  if [[ $ver != '1' ]] ; then
+    echo "****************************************************"
+    echo "*** thrift is not available"
+    echo "***   expecting 'thrift -version' to return $1"
+    echo "*** generated code will not be updated"
+    fail "****************************************************"
+  fi
+}
+
+checkThriftVersion() {
+  local v; v=$(getThriftVersionFromPom 2>/dev/null) \
+    || fail could not determine expected version of thrift from pom.xml file
+  requireThriftVersion "$v"
+}
+
+generateJava() {
+  # output directory is $1/gen-java; the rest of the args are *.thrift files
+  local t; t=$1; shift
+  mkdir -p "$t"
+  rm -rf "$t"/gen-java
+  for f in "$@"; do
+    thrift -o "$t" --gen java:generated_annotations=suppress "$f" \
+      || fail unable to generate java thrift classes
+  done
+}
+
+suppressWarnings() {
+  # function skipped, unless needed
+  return
+  # shellcheck disable=SC1004 # https://www.shellcheck.net/wiki/SC1004
+  # add dummy method to suppress "unnecessary suppress warnings" for classes
+  # which don't have any unused variables; this only affects classes, enums
+  # aren't affected
+  find "$1" -type f -name '*.java' -exec grep -Zl '^public class ' {} + \
+    | xargs -0 sed -i -e 's/^[}]$/  private static void unusedMethod() {}\
+}/'
+}
+
+addLicenseHeaders() {
+  find "$1" -type f -name '*.java' -exec "$0" 'attachLicense' '{}' ';'
+}
+
+moveSingleFile() {
+  # compare files with the destination, and only copy those that have changed
+  local src; src=$3
+  local dst; dst=$2/${src#$1/}
+  mkdir -p "$(dirname "$dst")"
+  if ! cmp -s "$src" "$dst" ; then
+    echo cp -f "$src" "$dst"
+    cp -f "$src" "$dst" || fail unable to copy files to java workspace
+  fi
+}
+
+moveGeneratedFiles() {
+  # copy generated files found in $1 to $2
+  find "$1" -type f -name '*.java' -exec "$0" 'moveSingleFile' "$1" "$2" '{}' ';'
+}
+
+if [[ $1 == 'attachLicense' || $1 == 'moveSingleFile' ]]; then
+  # this enables the function to be used in a find loop
+  "$@"
+else
+  checkThriftVersion
+  generateJava target src/main/thrift/*.thrift
+  suppressWarnings target/gen-java
+  addLicenseHeaders target/gen-java
+  moveGeneratedFiles target/gen-java src/main/java
+fi
diff --git a/pom.xml b/pom.xml
index 36dcf4d..eebd34c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -56,13 +56,15 @@
     <accumulo.version>2.0.0</accumulo.version>
     <curator.version>4.0.1</curator.version>
     <dropwizard.version>0.8.1</dropwizard.version>
+    <extraReleaseArguments>-P thrift</extraReleaseArguments>
     <!-- Prevent findbugs from runnning because it does not work with Java 11 and is configured to run by parent pom.  Spotbugs is configured in place of findbugs. -->
     <findbugs.skip>true</findbugs.skip>
     <hadoop.version>3.1.1</hadoop.version>
     <releaseProfiles>fluo-release</releaseProfiles>
     <slf4j.version>1.7.12</slf4j.version>
     <spotbugs.version>3.1.12</spotbugs.version>
-    <zookeeper.version>3.4.8</zookeeper.version>
+    <thrift.version>0.12.0</thrift.version>
+    <zookeeper.version>3.4.14</zookeeper.version>
   </properties>
   <dependencyManagement>
     <dependencies>
@@ -202,6 +204,11 @@
         <version>${hadoop.version}</version>
       </dependency>
       <dependency>
+        <groupId>org.apache.thrift</groupId>
+        <artifactId>libthrift</artifactId>
+        <version>${thrift.version}</version>
+      </dependency>
+      <dependency>
         <groupId>org.apache.zookeeper</groupId>
         <artifactId>zookeeper</artifactId>
         <version>${zookeeper.version}</version>
@@ -337,6 +344,11 @@
             <tagNameFormat>rel/fluo-@{project.version}</tagNameFormat>
           </configuration>
         </plugin>
+        <plugin>
+          <groupId>org.codehaus.mojo</groupId>
+          <artifactId>exec-maven-plugin</artifactId>
+          <version>1.6.0</version>
+        </plugin>
       </plugins>
     </pluginManagement>
     <plugins>