diff --git a/build-support/release/rat_exclude_files.txt b/build-support/release/rat_exclude_files.txt
index ea13868be1..298f28ce3d 100644
--- a/build-support/release/rat_exclude_files.txt
+++ b/build-support/release/rat_exclude_files.txt
@@ -10,6 +10,9 @@ pax_global_header
version.txt
build-support/release/rat_exclude_files.txt
docs/support/doxygen/client_api.footer.in
+java/gradlew
+java/gradle/gradle-wrapper.jar
+java/gradle/gradle-wrapper.properties
java/kudu-flume-sink/src/test/avro/testAvroKuduOperationsProducer.avsc
java/kudu-client/src/main/java/com/google/protobuf/ZeroCopyLiteralByteString.java
java/kudu-client/src/main/java/org/apache/kudu/client/AsyncKuduClient.java
diff --git a/java/.gitignore b/java/.gitignore
index fd62d76571..b418b4cf60 100644
--- a/java/.gitignore
+++ b/java/.gitignore
@@ -16,6 +16,7 @@
# under the License.
# Eclipse files
+.metadata/
.classpath
.project
.settings/
@@ -24,8 +25,13 @@
target/
dependency-reduced-pom.xml
+# Gradle build artifacts
+.gradle
+build
+
# IntelliJ
*.ipr
*.iws
*.iml
.idea/
+classes
diff --git a/java/README.md b/java/README.md
index 8bd8b85e38..3b65f27726 100644
--- a/java/README.md
+++ b/java/README.md
@@ -25,7 +25,7 @@ Building the Client
$ mvn package -DskipTests
-The client jar will can then be found at kudu-client/target.
+The client jar can then be found at kudu-client/target.
Running the Tests
------------------------------------------------------------
@@ -135,3 +135,56 @@ likely a bug in maven-protoc-plugin.
There's a simple workaround: delete the errant folder within
Eclipse and refresh the kudu-client project.
+
+Building with Gradle
+--------------------
+
+As an experiment a Gradle build definition also exists.
+In order to run the Gradle build you must install [Gradle|https://gradle.org/].
+If you would rather not install Gradle locally, you can use the
+[Gradle Wrapper|https://docs.gradle.org/current/userguide/gradle_wrapper.html]
+by replacing all references to gradle with gradlew.
+
+## Running a full build
+
+This will build all modules and run all "checks".
+
+$ gradle buildAll
+
+## Building the Client
+$ gradle :kudu-client:assemble
+
+The client jar can then be found at kudu-client/build/libs.
+
+## Running the Tests
+$ gradle test
+
+Integration tests, including tests which cover Hadoop integration,
+may be run with:
+
+$ gradle integrationTest
+
+*Note:* Integration tests may depend on built Kudu binaries.
+
+## Building the Kudu-Spark integration
+
+Builds with Spark 2.x with Scala 2.11 (the default) or
+Spark 1.x with Scala 2.10.
+
+$ gradle :kudu-spark:assemble
+$ gradle :kudu-spark:assemble -PscalaVersions=2.10.6
+
+## Installing to local maven repo
+
+$ gradle install
+
+## Clearing cached build state
+
+$ gradle clean
+
+## Discovering other tasks
+
+$ gradle tasks
+
+
+
diff --git a/java/build.gradle b/java/build.gradle
new file mode 100755
index 0000000000..6bd21fc7c9
--- /dev/null
+++ b/java/build.gradle
@@ -0,0 +1,48 @@
+// 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 file is the entry-point for the gradle build and contains
+// common logic for the various subprojects in the build.
+
+// Load the buildscript file to apply dependencies needed for the gradle build itself.
+buildscript { apply from: file("gradle/buildscript.gradle"), to: buildscript }
+
+// Plugins and scripts applied at the root level only, instead of per module.
+apply plugin: "idea"
+apply plugin: "eclipse"
+apply from: "$rootDir/gradle/properties.gradle"
+apply from: "$rootDir/gradle/dependencies.gradle"
+apply from: "$rootDir/gradle/wrapper.gradle"
+
+subprojects {
+ // Plugins and scripts are applied in the natural "build order"
+ // they are used to ensure there are no dependency issues.
+ // These are common to all subprojects. However, subprojects may
+ // include their own plugins and scripts as well.
+ apply plugin: "java"
+ apply from: "$rootDir/gradle/scopes.gradle"
+ apply from: "$rootDir/gradle/compile.gradle"
+ apply from: "$rootDir/gradle/tests.gradle"
+ apply from: "$rootDir/gradle/quality.gradle"
+ apply from: "$rootDir/gradle/artifacts.gradle"
+ apply from: "$rootDir/gradle/publishing.gradle"
+
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+}
\ No newline at end of file
diff --git a/java/gradle.properties b/java/gradle.properties
new file mode 100755
index 0000000000..2ad95e77d2
--- /dev/null
+++ b/java/gradle.properties
@@ -0,0 +1,41 @@
+# 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 file contains project properties.
+# More about how to use the gradle.properties file can be read here:
+# https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_configuration_properties
+
+group = org.apache.kudu
+version = 1.5.0-SNAPSHOT
+url = https://kudu.apache.org/
+scmUrl = git://git.apache.org/kudu.git
+issueTrackerUrl = https://issues.apache.org/jira/projects/KUDU
+
+javaSourceCompatibility = 1.7
+encoding = UTF-8
+
+# Maximum parallel forks to use while unit testing.
+maxParallelForks = 1
+
+# Flags to speed up the gradle build.
+# https://docs.gradle.org/current/userguide/build_environment.html
+org.gradle.daemon=true
+# The below configurations are experimental but a nice performance boost.
+# org.gradle.caching=true
+# org.gradle.configureondemand=true
+# org.gradle.parallel=true
+# org.gradle.workers.max=4
\ No newline at end of file
diff --git a/java/gradle/artifacts.gradle b/java/gradle/artifacts.gradle
new file mode 100755
index 0000000000..69a74ab713
--- /dev/null
+++ b/java/gradle/artifacts.gradle
@@ -0,0 +1,57 @@
+// 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 file contains common tasks and configuration for artifact generation.
+
+// Create a configuration so that the test jar can be referenced in other modules.
+configurations.create("test")
+
+task testJar(type: Jar, dependsOn: testClasses, group: "Build") {
+ description = "Assembles a jar archive containing the test classes."
+ from sourceSets.test.output
+ classifier = "tests"
+ extension "jar"
+}
+
+task sourcesJar(type: Jar, dependsOn: classes, group: "Build") {
+ description = "Assembles a jar archive containing the main source."
+ from sourceSets.main.allSource
+ classifier "sources"
+ extension "jar"
+}
+
+task testSourcesJar(type: Jar, dependsOn: testJar, group: "Build") {
+ description = "Assembles a jar archive containing the test source."
+ from sourceSets.test.allSource
+ classifier "test-sources"
+ extension "jar"
+}
+
+task javadocJar(type: Jar, dependsOn: javadoc, group: "Build") {
+ description = "Assembles a jar archive containing the javadoc."
+ from javadoc.destinationDir
+ classifier "javadoc"
+ extension "jar"
+}
+
+artifacts {
+ test testJar
+ archives testJar
+ archives sourcesJar
+ archives testSourcesJar
+ archives javadocJar
+}
\ No newline at end of file
diff --git a/java/gradle/buildscript.gradle b/java/gradle/buildscript.gradle
new file mode 100644
index 0000000000..6f062f8e11
--- /dev/null
+++ b/java/gradle/buildscript.gradle
@@ -0,0 +1,37 @@
+// 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 file contains the dependencies required for the gradle build itself.
+
+repositories {
+ mavenCentral()
+ jcenter()
+ maven { url "http://clojars.org/repo" } // Only used for the clojure plugin below.
+ maven { url "http://repo.spring.io/plugins-release" } // Only used for the propdeps plugin below.
+ maven { url "https://plugins.gradle.org/m2/" }
+}
+
+// Manage plugin dependencies since the plugin block can't be used in included build scripts yet.
+// For more details see: https://docs.gradle.org/current/userguide/plugins.html#plugins_dsl_limitations
+dependencies {
+ classpath "com.commercehub.gradle.plugin:gradle-avro-plugin:0.9.0"
+ classpath "com.github.ben-manes:gradle-versions-plugin:0.15.0"
+ classpath "com.github.jengelman.gradle.plugins:shadow:2.0.1"
+ classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.1"
+ classpath "com.netflix.nebula:nebula-clojure-plugin:4.1.0"
+ classpath "io.spring.gradle:propdeps-plugin:0.0.9.RELEASE"
+}
\ No newline at end of file
diff --git a/java/gradle/compile.gradle b/java/gradle/compile.gradle
new file mode 100644
index 0000000000..823775af35
--- /dev/null
+++ b/java/gradle/compile.gradle
@@ -0,0 +1,37 @@
+// 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 file contains common compiler configurations.
+
+// Java Configuration
+tasks.withType(JavaCompile) {
+ sourceCompatibility = javaSourceCompatibility
+ options.encoding = encoding // make sure the encoding is defined by the project and not the system default.
+ options.incremental = true // enable incremental compilation.
+}
+
+// Scala configuration
+tasks.withType(ScalaCompile) {
+ sourceCompatibility = javaSourceCompatibility
+ scalaCompileOptions.encoding = encoding // make sure the encoding is defined by the project and not the system default.
+ scalaCompileOptions.additionalParameters = [
+ // Emit warning and location for usages of features that should be imported explicitly.
+ "-feature",
+ // Emit various static analysis warnings.
+ "-Xlint"
+ ]
+}
\ No newline at end of file
diff --git a/java/gradle/dependencies.gradle b/java/gradle/dependencies.gradle
new file mode 100755
index 0000000000..f62015cc1e
--- /dev/null
+++ b/java/gradle/dependencies.gradle
@@ -0,0 +1,105 @@
+// 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 file contains all of the dependencies required for the build.
+// Centrally locating all of the dependencies ensures each subproject
+// uses the same dependency version for all dependencies used.
+
+ext {
+ versions = [:]
+ libs = [:]
+ // All supported scala versions.
+ scalaVersions = propertyWithDefault("scalaVersions", "2.11.8,2.10.6").split(",")
+}
+
+versions += [
+ async : "1.4.1",
+ avro : "1.8.1",
+ clojure : "1.8.0",
+ clojureToolsCli: "0.3.5",
+ commonsIo : "2.5",
+ findbugs : "3.0.1",
+ flume : "1.6.0",
+ gradle : "4.0.2",
+ guava : "20.0",
+ hadoop : "2.8.1",
+ hamcrest : "1.3",
+ jepsen : "0.1.3",
+ jsr305 : "3.0.2",
+ junit : "4.12",
+ log4j : "1.2.17",
+ mockito : "2.8.47",
+ murmur : "1.0.0",
+ netty : "3.10.6.Final",
+ pmd : "5.8.1",
+ protobuf : "3.3.0",
+ scalatest : "3.0.3",
+ slf4j : "1.7.25",
+ yetus : "0.5.0"
+]
+
+// Log the Gradle version used vs defined.
+if (gradle.gradleVersion != versions.gradle) {
+ println "Using gradle version $gradle.gradleVersion (Build defines $versions.gradle)"
+}
+
+// Set the Scala version.
+// The first Scala version in the scalaVersions list is the default.
+versions["scala"] = scalaVersions.first()
+// Add base Scala version
+versions["scalaBase"] = versions.scala.substring(0, versions.scala.lastIndexOf("."))
+
+// Set the Spark version based on the Scala version.
+def spark1Version = "1.6.3"
+def spark2Version = "2.1.1"
+if ("$versions.scalaBase" == "2.10") {
+ versions["spark"] = spark1Version
+} else {
+ versions["spark"] = spark2Version
+}
+versions["sparkBase"] = versions.spark.substring(0, versions.spark.indexOf("."))
+// Log for debugging
+logger.info("Configuring Scala version: $versions.scala with Spark version: $versions.spark")
+
+libs += [
+ async : "com.stumbleupon:async:$versions.async",
+ avro : "org.apache.avro:avro:$versions.avro",
+ clojure : "org.clojure:clojure:$versions.clojure",
+ clojureToolsCli : "org.clojure:tools.cli:$versions.clojureToolsCli",
+ commonsIo : "commons-io:commons-io:$versions.commonsIo",
+ flumeConfiguration: "org.apache.flume:flume-ng-configuration:$versions.flume",
+ flumeCore : "org.apache.flume:flume-ng-core:$versions.flume",
+ guava : "com.google.guava:guava:$versions.guava",
+ hadoopClient : "org.apache.hadoop:hadoop-client:$versions.hadoop",
+ hamcrestCore : "org.hamcrest:hamcrest-core:$versions.hamcrest",
+ jepsen : "jepsen:jepsen:$versions.jepsen",
+ jsr305 : "com.google.code.findbugs:jsr305:$versions.jsr305",
+ junit : "junit:junit:$versions.junit",
+ log4j : "log4j:log4j:$versions.log4j",
+ mockitoCore : "org.mockito:mockito-core:$versions.mockito",
+ murmur : "com.sangupta:murmur:$versions.murmur",
+ netty : "io.netty:netty:$versions.netty",
+ protobufJava : "com.google.protobuf:protobuf-java:$versions.protobuf",
+ protoc : "com.google.protobuf:protoc:$versions.protobuf",
+ scalaLibrary : "org.scala-lang:scala-library:$versions.scala",
+ scalatest : "org.scalatest:scalatest_$versions.scalaBase:$versions.scalatest",
+ slf4jApi : "org.slf4j:slf4j-api:$versions.slf4j",
+ slf4jLog4j12 : "org.slf4j:slf4j-log4j12:$versions.slf4j",
+ sparkCore : "org.apache.spark:spark-core_$versions.scalaBase:$versions.spark",
+ sparkSql : "org.apache.spark:spark-sql_$versions.scalaBase:$versions.spark",
+ yetusAnnotations : "org.apache.yetus:audience-annotations:$versions.yetus"
+]
\ No newline at end of file
diff --git a/java/gradle/properties.gradle b/java/gradle/properties.gradle
new file mode 100644
index 0000000000..1c89214f8b
--- /dev/null
+++ b/java/gradle/properties.gradle
@@ -0,0 +1,53 @@
+// 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 file contains methods to be used in the build to load and
+// set build properties consistently.
+
+// ext makes these methods callable project wide
+ext {
+ // A common method to handle loading gradle properties with a default when
+ // no definition is found. The property value is determined by the following
+ // priority order (top is highest priority):
+ // - gradle property (-Pproperty=value)
+ // - system property (-Dproperty=value)
+ // - default value
+ // See more details on gradle property handling here:
+ // https://docs.gradle.org/current/userguide/build_environment.html#sec:gradle_properties_and_system_properties
+ propertyWithDefault = { property, defaultValue ->
+ def value = defaultValue
+ def systemValue = System.getProperty(property)
+ if (systemValue != null) {
+ value = systemValue
+ }
+ def projectValue = project.hasProperty(property) ? project.getProperty(property) : null
+ if (projectValue != null) {
+ value = projectValue
+ }
+ logger.info("Resolved property $property with final value $value " +
+ "[defaultValue=$defaultValue, systemValue=$systemValue, projectValue=$projectValue]")
+ return value
+ }
+
+ // Returns true if the property has been set, otherwise false.
+ propertyExists = { property ->
+ if (System.getProperty(property) != null || project.hasProperty(property)) {
+ return true
+ }
+ return false
+ }
+}
\ No newline at end of file
diff --git a/java/gradle/protobuf.gradle b/java/gradle/protobuf.gradle
new file mode 100644
index 0000000000..f3d84bcfcc
--- /dev/null
+++ b/java/gradle/protobuf.gradle
@@ -0,0 +1,34 @@
+// 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 file contains the common protobuf plugin configuration.
+
+apply plugin: "com.google.protobuf"
+
+// Use the maven protoc artifact instead of local.
+protobuf {
+ protoc {
+ artifact = libs.protoc
+ }
+}
+
+// Configure Intellij to see the generated classes.
+idea {
+ module {
+ generatedSourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java")
+ }
+}
\ No newline at end of file
diff --git a/java/gradle/publishing.gradle b/java/gradle/publishing.gradle
new file mode 100644
index 0000000000..5b3ba2e8ad
--- /dev/null
+++ b/java/gradle/publishing.gradle
@@ -0,0 +1,62 @@
+// 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 file contains common tasks and configuration for artifact publishing.
+
+apply plugin: "maven"
+apply plugin: "signing"
+
+// Only sign artifacts if skipSigning is false,
+// the version is not a snapshot, and we are uploading them to maven.
+// This allows simplified builds and local maven installs.
+def skipSigning = propertyExists("skipSigning")
+def shouldSign = !skipSigning && !version.endsWith("SNAPSHOT") && project.gradle.startParameter.taskNames.any { it.contains("upload") }
+def mavenUrl = propertyWithDefault("mavenUrl", "")
+def mavenUsername = propertyWithDefault("mavenUsername", "")
+def mavenPassword = propertyWithDefault("mavenPassword", "")
+
+uploadArchives {
+ repositories {
+ signing {
+ required { shouldSign }
+ sign configurations.archives
+ mavenDeployer {
+ beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+ repository(url: "${mavenUrl}") {
+ authentication(userName: "${mavenUsername}", password: "${mavenPassword}")
+ }
+ }
+ }
+ }
+}
+
+// Add the install task to the "Upload" group so it's visible in the tasks output.
+install.group = "Upload"
+
+// Sort the generated maven dependencies to make pom comparisons easier.
+tasks.withType(Upload) {
+ def installer = install.repositories.mavenInstaller
+ def deployer = uploadArchives.repositories.mavenDeployer
+
+ [installer, deployer]*.pom*.whenConfigured { pom ->
+ pom.dependencies = pom.dependencies.sort { dep ->
+ "$dep.scope:$dep.optional:$dep.groupId:$dep.artifactId"
+ }
+ }
+}
+
+
diff --git a/java/gradle/quality.gradle b/java/gradle/quality.gradle
new file mode 100644
index 0000000000..1f0759709c
--- /dev/null
+++ b/java/gradle/quality.gradle
@@ -0,0 +1,85 @@
+// 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 file contains common tasks and configuration for checking the quality of the code.
+
+apply plugin: "checkstyle" // Ensures Java code follows the defined coding style.
+apply plugin: "findbugs" // Performs static code analysis to look for bugs in Java code.
+apply plugin: "pmd" // Performs static code analysis to look for common code smells in Java code.
+apply plugin: "com.github.ben-manes.versions" // Provides a task to determine which dependencies have updates.
+
+checkstyle {
+ configFile = file("$rootDir/kudu_style.xml")
+ configProperties = [
+ "checkstyle.suppressions.file" : "$rootDir/checkstyle_suppressions.xml"
+ ]
+ ignoreFailures = true
+ showViolations = true
+}
+
+// Create an aggregate checkstyle task.
+// This simplifies running checkstyle on all the code by only needing one task instead of multiple in your command.
+task checkstyle(dependsOn: [checkstyleMain, checkstyleTest, checkstyleIntegrationTest], group: "Verification") {
+ description = "Run Checkstyle analysis."
+}
+
+findbugs {
+ toolVersion = versions.findbugs
+ ignoreFailures = true
+ effort = "max"
+}
+
+tasks.withType(FindBugs) {
+ reports {
+ xml.enabled false
+ html.enabled true
+ }
+}
+
+// Create an aggregate findbugs task.
+// This simplifies running findbugs on all the code by only needing one task instead of multiple in your command.
+task findbugs(dependsOn: [findbugsMain, findbugsTest, findbugsIntegrationTest], group: "Verification") {
+ description = "Run FindBugs analysis."
+}
+
+pmd {
+ toolVersion = versions.pmd
+ ignoreFailures = true
+}
+
+// Create an aggregate pmd task.
+// This simplifies running pmd on all the code by only needing one task instead of multiple in your command.
+task pmd(dependsOn: [pmdMain, pmdTest, pmdIntegrationTest], group: "Verification") {
+ description = "Run PMD analysis."
+}
+
+// Configure the versions plugin to only show dependency updates for released versions.
+dependencyUpdates {
+ revision = "release"
+ resolutionStrategy = {
+ componentSelection { rules ->
+ rules.all { ComponentSelection selection ->
+ boolean rejected = ["snap", "alpha", "beta", "rc", "cr", "m"].any { qualifier ->
+ selection.candidate.version ==~ /(?i).*[.-]${qualifier}[.\d-]*/
+ }
+ if (rejected) {
+ selection.reject("Release candidate")
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/gradle/scopes.gradle b/java/gradle/scopes.gradle
new file mode 100644
index 0000000000..10bede3a3c
--- /dev/null
+++ b/java/gradle/scopes.gradle
@@ -0,0 +1,23 @@
+// 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 file adds provided scope and optional maven support.
+
+apply plugin: "propdeps"
+apply plugin: "propdeps-eclipse"
+apply plugin: "propdeps-idea"
+apply plugin: "propdeps-maven"
diff --git a/java/gradle/shadow.gradle b/java/gradle/shadow.gradle
new file mode 100644
index 0000000000..3663cc7d3f
--- /dev/null
+++ b/java/gradle/shadow.gradle
@@ -0,0 +1,110 @@
+// 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 file contains tasks and configuration to support shading dependencies
+// consistently when a subproject requires shaded artifacts.
+
+import org.gradle.api.internal.artifacts.publish.ArchivePublishArtifact
+
+apply plugin: "com.github.johnrengelman.shadow"
+
+tasks.remove(knows) // Remove "easter egg" knows task.
+shadowJar.group = "" // Hide shadowJar task since it's used by the default build.
+
+// Configure a shaded jar to replace the default jar
+shadowJar.classifier = null // Configure shadow jar to have the default classifier.
+jar.finalizedBy(shadowJar) // Generate the shaded jar anytime the jar task is run.
+jar.classifier = "unshaded" // Add an unshaded classifier to the default jar.
+
+// Add the shadowJar to the published artifacts.
+artifacts {
+ archives shadowJar
+}
+
+// Remove the unshaded jar from the published artifacts.
+configurations.archives.artifacts.removeAll {
+ it instanceof ArchivePublishArtifact && it.archiveTask == jar
+}
+
+// Ensure we always relocate these shaded dependencies to the same
+// location across all modules.
+shadowJar {
+ relocate "com.google.common", "org.apache.kudu.shaded.com.google.common"
+ relocate "com.google.protobuf", "org.apache.kudu.shaded.com.google.protobuf"
+ relocate "com.google.thirdparty", "org.apache.kudu.shaded.com.google.thirdparty"
+ relocate "com.sangupta", "org.apache.kudu.shaded.com.sangupta"
+ relocate "org.jboss.netty", "org.apache.kudu.shaded.org.jboss.netty"
+}
+
+// ------------------------------------------------------------------
+// Everything below is a "hack" to support partial shading and
+// accurate pom generation. At some point this logic should exist
+// in the shadow plugin itself.
+// ------------------------------------------------------------------
+
+// Add a configuration to support unshaded compile dependencies.
+// By default shadow assumes all dependencies are shaded.
+configurations.create("compileUnshaded")
+configurations.shadow.extendsFrom(configurations.compileUnshaded)
+configurations.compile.extendsFrom(configurations.compileUnshaded)
+
+// Remove the shaded dependencies from the generated pom.
+// This hack allows the project to support partially shaded jars,
+// where the shadow plugin by default would remove all compile and runtime dependencies.
+tasks.withType(Upload) {
+ def installer = install.repositories.mavenInstaller
+ def deployer = uploadArchives.repositories.mavenDeployer
+
+ // Handle install and deploy in the same way.
+ [installer, deployer]*.pom*.whenConfigured { pom ->
+ def filter = shadowJar.getDependencyFilter()
+ def configs = shadowJar.getConfigurations()
+
+ def shadowDependencies = configs.collectMany {
+ // Find all dependencies included in the shadow configuration.
+ it.resolvedConfiguration.firstLevelModuleDependencies.findAll {
+ filter.isIncluded(it)
+ }
+ }
+
+ // Remove the shadow dependencies from the pom.
+ shadowDependencies.each { shaded ->
+ pom.dependencies.removeAll { dep ->
+ dep.groupId == shaded.getModuleGroup() &&
+ dep.artifactId == shaded.getModuleName() &&
+ dep.version == shaded.getModuleVersion()
+ }
+ }
+
+ // Add the explicitly unshaded dependencies from the pom.
+ def unshadedDependencies = project.configurations.compileUnshaded.resolvedConfiguration.firstLevelModuleDependencies
+ unshadedDependencies.each { unshaded ->
+ // to avoid class loading problems
+ def dependency = pom.model.class.classLoader.loadClass("org.apache.maven.model.Dependency").newInstance()
+ dependency.setGroupId(unshaded.getModuleGroup())
+ dependency.setArtifactId(unshaded.getModuleName())
+ dependency.setVersion(unshaded.getModuleVersion())
+ dependency.setScope("compile")
+ pom.dependencies.add(dependency)
+ }
+
+ // Re-sort the generated maven dependencies to make pom comparisons easier.
+ pom.dependencies = pom.dependencies.sort { dep ->
+ "$dep.scope:$dep.optional:$dep.groupId:$dep.artifactId"
+ }
+ }
+}
\ No newline at end of file
diff --git a/java/gradle/tests.gradle b/java/gradle/tests.gradle
new file mode 100644
index 0000000000..01e3c0d6fb
--- /dev/null
+++ b/java/gradle/tests.gradle
@@ -0,0 +1,80 @@
+// 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 file contains common tasks and configuration for unit and integration tests.
+
+// Support parallel unit test execution.
+test {
+ maxParallelForks = propertyWithDefault("maxParallelForks", "1").toInteger()
+}
+
+// Log all test events.
+tasks.withType(Test) {
+ testLogging {
+ events "passed", "skipped", "failed"
+ exceptionFormat = "full"
+ }
+}
+
+// Adds pattern based integration test support.
+// All test files matching the pattern "**/*IT*.java" will be run after the the other tests.
+sourceSets {
+ test {
+ java {
+ exclude "**/*IT*.java"
+ }
+ }
+ integrationTest {
+ java {
+ srcDirs = ["src/test/java"]
+ include "**/*IT*.java"
+ }
+ compileClasspath += main.output + test.output
+ runtimeClasspath += main.output + test.output
+ }
+}
+plugins.withType(ScalaPlugin) {
+ sourceSets {
+ test {
+ scala {
+ exclude "**/*IT*.scala"
+ }
+ }
+ integrationTest {
+ scala {
+ srcDirs = ["src/test/scala"]
+ include "**/*IT*.scala"
+ }
+ compileClasspath += main.output + test.output
+ runtimeClasspath += main.output + test.output
+ }
+ }
+}
+
+configurations {
+ integrationTestCompile.extendsFrom testCompile
+ integrationTestRuntime.extendsFrom testRuntime
+}
+
+task integrationTest(type: Test, group: "Verification") {
+ description = "Runs the integration tests."
+ testClassesDirs = sourceSets.integrationTest.output.classesDirs
+ classpath = sourceSets.integrationTest.runtimeClasspath
+ maxParallelForks = 1
+ mustRunAfter test
+}
+check.dependsOn(integrationTest)
\ No newline at end of file
diff --git a/java/gradle/wrapper.gradle b/java/gradle/wrapper.gradle
new file mode 100644
index 0000000000..4efab86ef3
--- /dev/null
+++ b/java/gradle/wrapper.gradle
@@ -0,0 +1,64 @@
+// 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 file contains tasks for the gradle wrapper generation.
+
+// Ensure the wrapper script is generated based on the version defined in the project
+// and not the version installed on the machine running the task.
+// Read more about the wrapper here: https://docs.gradle.org/current/userguide/gradle_wrapper.html
+task wrapper(type: Wrapper) {
+ gradleVersion = versions.gradle
+}
+
+// Custom task to inject support for downloading the gradle wrapper jar if it doesn't exist.
+// This allows us to avoid checking in the jar to our repository.
+task bootstrapWrapper() {
+ // In the doLast block so this runs when the task is called and not during project configuration.
+ doLast {
+ def wrapperJarPath = "\$APP_HOME/gradle/wrapper/gradle-wrapper.jar"
+ // Leverages the wrapper jar checked into the gradle project on github because the jar isn't available elsewhere.
+ def wrapperJarUrl = "https://raw.githubusercontent.com/gradle/gradle/v${versions.gradle}/gradle/wrapper/gradle-wrapper.jar"
+
+
+ def boostrapString = """
+ if [[ ! -e $wrapperJarPath ]]; then
+ curl -o $wrapperJarPath $wrapperJarUrl
+ fi
+ """.stripIndent()
+
+ def wrapperScript = file("$rootDir/gradlew")
+ def wrapperLines = wrapperScript.readLines()
+ wrapperScript.withPrintWriter { out ->
+ def bootstrapWritten = false
+ wrapperLines.each { line ->
+ // Print the wrapper bootstrap before the first usage of the wrapper jar.
+ if (!bootstrapWritten && line.contains("gradle-wrapper.jar")) {
+ out.println(boostrapString)
+ bootstrapWritten = true
+ }
+ out.println(line)
+ }
+ }
+ }
+}
+wrapper.finalizedBy bootstrapWrapper
+
+// Remove the generated batch file since we don't test building in the Windows environment.
+task removeWindowScript(type: Delete) {
+ delete "$rootDir/gradlew.bat"
+}
+wrapper.finalizedBy removeWindowScript
\ No newline at end of file
diff --git a/java/gradle/wrapper/gradle-wrapper.properties b/java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..fc47300fde
--- /dev/null
+++ b/java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Aug 02 23:12:26 CDT 2017
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0.2-all.zip
diff --git a/java/gradlew b/java/gradlew
new file mode 100755
index 0000000000..93678fd1d6
--- /dev/null
+++ b/java/gradlew
@@ -0,0 +1,177 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+
+if [[ ! -e $APP_HOME/gradle/wrapper/gradle-wrapper.jar ]]; then
+ curl -o $APP_HOME/gradle/wrapper/gradle-wrapper.jar https://raw.githubusercontent.com/gradle/gradle/v4.0.2/gradle/wrapper/gradle-wrapper.jar
+fi
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/java/kudu-client-tools/build.gradle b/java/kudu-client-tools/build.gradle
new file mode 100644
index 0000000000..d8627c3928
--- /dev/null
+++ b/java/kudu-client-tools/build.gradle
@@ -0,0 +1,32 @@
+// 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.
+
+apply from: "$rootDir/gradle/shadow.gradle"
+
+dependencies {
+ compile project(":kudu-mapreduce")
+ compile libs.yetusAnnotations
+ compile libs.slf4jApi
+
+ provided libs.hadoopClient
+
+ testCompile project(path: ":kudu-client", configuration: "shadowTest")
+ testCompile project(path: ":kudu-mapreduce", configuration: "test")
+ testCompile libs.junit
+ testCompile libs.log4j
+ testCompile libs.slf4jLog4j12
+}
\ No newline at end of file
diff --git a/java/kudu-client/build.gradle b/java/kudu-client/build.gradle
new file mode 100644
index 0000000000..b266073478
--- /dev/null
+++ b/java/kudu-client/build.gradle
@@ -0,0 +1,70 @@
+// 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.
+
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
+
+apply from: "$rootDir/gradle/protobuf.gradle"
+apply from: "$rootDir/gradle/shadow.gradle"
+
+dependencies {
+ // Not shaded in the client JAR because it's part of the public API.
+ compileUnshaded(libs.async) {
+ // async uses versions ranges for slf4j making builds non-deterministic.
+ // Remove this once the following is merged: https://github.com/OpenTSDB/async/pull/8
+ exclude group: "org.slf4j", module: "slf4j-api"
+ }
+ compileUnshaded libs.slf4jApi
+ compileUnshaded libs.yetusAnnotations
+
+ compile libs.guava
+ compile libs.murmur
+ compile libs.netty
+ compile libs.protobufJava
+
+ optional libs.jsr305
+
+ testCompile libs.commonsIo
+ testCompile libs.hamcrestCore
+ testCompile libs.junit
+ testCompile libs.log4j
+ testCompile libs.mockitoCore
+ testCompile libs.slf4jLog4j12
+}
+
+// Add protobuf files to the proto source set.
+sourceSets {
+ main {
+ proto {
+ srcDir "${project.rootDir}/../src"
+ // Excluded any test proto files
+ exclude "**/*test*.proto"
+ }
+ }
+}
+
+// Configure a shaded test jar for use in the other modules.
+// We only do this for kudu-client because it has common test utilities.
+task shadowTestJar(type: ShadowJar) {
+ classifier = "tests-shaded"
+ from sourceSets.test.output
+ configurations = [project.configurations.testRuntime]
+}
+// Create a configuration so that the shaded test jar can be referenced in other modules.
+configurations.create("shadowTest")
+artifacts {
+ shadowTest shadowTestJar
+}
\ No newline at end of file
diff --git a/java/kudu-flume-sink/build.gradle b/java/kudu-flume-sink/build.gradle
new file mode 100644
index 0000000000..79df593c76
--- /dev/null
+++ b/java/kudu-flume-sink/build.gradle
@@ -0,0 +1,33 @@
+// 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.
+
+// Add the Avro plugin to support code generation from schema files.
+apply plugin: "com.commercehub.gradle.plugin.avro"
+
+dependencies {
+ compile project(path: ":kudu-client", configuration: "shadow")
+ compile libs.slf4jApi
+ compile libs.yetusAnnotations
+
+ provided libs.avro
+ provided libs.flumeConfiguration
+ provided libs.flumeCore
+ provided libs.hadoopClient
+
+ testCompile project(path: ":kudu-client", configuration: "shadowTest")
+ testCompile libs.junit
+}
\ No newline at end of file
diff --git a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/AvroKuduOperationsProducer.java b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/AvroKuduOperationsProducer.java
index ac87e295b6..b6241bb70f 100644
--- a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/AvroKuduOperationsProducer.java
+++ b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/AvroKuduOperationsProducer.java
@@ -59,7 +59,7 @@
* body as an Avro record and mapping its fields to columns in a Kudu table.
*
*
Avro Kudu Operations Producer configuration parameters
- *
+ *
* Property Name |
* Default |
* Required? |
diff --git a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/KuduSink.java b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/KuduSink.java
index 17706f716f..42f05423fb 100644
--- a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/KuduSink.java
+++ b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/KuduSink.java
@@ -57,7 +57,7 @@
*
* Flume Kudu Sink configuration parameters
*
- *
+ *
* Property Name | Default | Required? | Description |
* channel | | Yes | The name of the Flume channel to read. |
* type | | Yes |
diff --git a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKeyedKuduOperationsProducer.java b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKeyedKuduOperationsProducer.java
index c216f99f01..b4217716be 100644
--- a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKeyedKuduOperationsProducer.java
+++ b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKeyedKuduOperationsProducer.java
@@ -43,7 +43,7 @@
*
* Simple Keyed Kudu Operations Producer configuration parameters
*
- *
+ *
*
* Property Name |
* Default |
diff --git a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKuduOperationsProducer.java b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKuduOperationsProducer.java
index 4fa8bd8bb0..acd74e11ff 100644
--- a/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKuduOperationsProducer.java
+++ b/java/kudu-flume-sink/src/main/java/org/apache/kudu/flume/sink/SimpleKuduOperationsProducer.java
@@ -39,7 +39,7 @@
*
* Simple Kudu Event Producer configuration parameters
*
- *
+ *
*
* Property Name |
* Default |
diff --git a/java/kudu-jepsen/build.gradle b/java/kudu-jepsen/build.gradle
new file mode 100644
index 0000000000..fe55c21008
--- /dev/null
+++ b/java/kudu-jepsen/build.gradle
@@ -0,0 +1,66 @@
+// 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.
+
+apply plugin: "nebula.clojure"
+
+// Skip kudu-jepsen module tasks unless "Jepsen" property is passed.
+if (!project.hasProperty("jepsen")) {
+ gradle.taskGraph.whenReady {
+ gradle.taskGraph.allTasks.each {
+ it.onlyIf { it.project != project }
+ }
+ }
+}
+
+repositories {
+ maven { url "http://clojars.org/repo/" }
+}
+
+dependencies {
+ compile project(path: ":kudu-client", configuration: "shadow")
+ compile project(path: ":kudu-client", configuration: "shadowTest")
+ compile libs.clojure
+ compile libs.clojureToolsCli
+ compile libs.jepsen
+ compile libs.yetusAnnotations
+}
+
+compileClojure {
+ aotCompile = true
+}
+// Jepsen tests require specific infrastructure and do not run as part of the regular tests.
+clojureTest.enabled = false
+
+// Run the Jepsen tests.
+task runJepsen(type: JavaExec) {
+ def masterNodes = propertyWithDefault("masterNodes", "m0")
+ def tserverNodes = propertyWithDefault("tserverNodes", "t0,t1,t2,t3,t4")
+ def sshKeyPath = propertyWithDefault("sshKeyPath", "")
+ def iterNum = propertyWithDefault("iterNum", "1")
+ classpath sourceSets.main.clojure.srcDirs,
+ sourceSets.test.clojure.srcDirs,
+ sourceSets.test.runtimeClasspath,
+ sourceSets.main.runtimeClasspath,
+ main = "clojure.main"
+ args = [
+ "$projectDir/src/utils/kudu_test_runner.clj",
+ "--masters=${masterNodes}",
+ "--tservers=${tserverNodes}",
+ "--ssh-key-path=${sshKeyPath}",
+ "--iter-num=${iterNum}"
+ ]
+}
\ No newline at end of file
diff --git a/java/kudu-mapreduce/build.gradle b/java/kudu-mapreduce/build.gradle
new file mode 100644
index 0000000000..cfeb26b999
--- /dev/null
+++ b/java/kudu-mapreduce/build.gradle
@@ -0,0 +1,34 @@
+// 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.
+
+dependencies {
+ compile project(path: ":kudu-client", configuration: "shadow")
+ compile(libs.async) {
+ // async uses versions ranges for slf4j making builds non-deterministic.
+ // Remove this once the following is merged: https://github.com/OpenTSDB/async/pull/8
+ exclude group: "org.slf4j", module: "slf4j-api"
+ }
+ compile libs.slf4jApi
+ compile libs.yetusAnnotations
+
+ provided libs.hadoopClient
+
+ testCompile project(path: ":kudu-client", configuration: "shadowTest")
+ testCompile libs.junit
+ testCompile libs.log4j
+ testCompile libs.slf4jLog4j12
+}
\ No newline at end of file
diff --git a/java/kudu-spark-tools/build.gradle b/java/kudu-spark-tools/build.gradle
new file mode 100644
index 0000000000..adf94b7b76
--- /dev/null
+++ b/java/kudu-spark-tools/build.gradle
@@ -0,0 +1,37 @@
+// 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.
+
+apply plugin: "scala"
+apply from: "$rootDir/gradle/shadow.gradle"
+
+dependencies {
+ compile project(path: ":kudu-client", configuration: "shadow")
+ compile project(path: ":kudu-client-tools", configuration: "shadow")
+ compile project(path: ":kudu-spark", configuration: "shadow")
+ compile libs.slf4jApi
+
+ provided libs.scalaLibrary
+ provided libs.sparkCore
+ provided libs.sparkSql
+
+ testCompile project(path: ":kudu-client", configuration: "shadowTest")
+ testCompile project(path: ":kudu-spark", configuration: "test")
+ testCompile libs.junit
+ testCompile libs.log4j
+ testCompile libs.scalatest
+ testCompile libs.slf4jLog4j12
+}
\ No newline at end of file
diff --git a/java/kudu-spark-tools/pom.xml b/java/kudu-spark-tools/pom.xml
index e0aa13b21a..c2eb57fe36 100644
--- a/java/kudu-spark-tools/pom.xml
+++ b/java/kudu-spark-tools/pom.xml
@@ -132,6 +132,12 @@
${project.build.sourceEncoding}
${scala-2.11.version}
+
+
+ -feature
+
+ -Xlint
+
diff --git a/java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/IntegrationTestBigLinkedListTest.scala b/java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/ITBigLinkedListTest.scala
similarity index 97%
rename from java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/IntegrationTestBigLinkedListTest.scala
rename to java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/ITBigLinkedListTest.scala
index 9d1faa57d9..6b34a5a44e 100644
--- a/java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/IntegrationTestBigLinkedListTest.scala
+++ b/java/kudu-spark-tools/src/test/scala/org/apache/kudu/spark/tools/ITBigLinkedListTest.scala
@@ -28,7 +28,7 @@ import org.scalatest.{FunSuite, Matchers}
import scala.collection.JavaConverters._
@RunWith(classOf[JUnitRunner])
-class IntegrationTestBigLinkedListTest extends FunSuite with TestContext with Matchers {
+class ITBigLinkedListTest extends FunSuite with TestContext with Matchers {
test("Spark ITBLL") {
Generator.testMain(Array("--tasks=2",
diff --git a/java/kudu-spark/build.gradle b/java/kudu-spark/build.gradle
new file mode 100644
index 0000000000..0ce65acc73
--- /dev/null
+++ b/java/kudu-spark/build.gradle
@@ -0,0 +1,54 @@
+// 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.
+
+apply plugin: "scala"
+apply from: "$rootDir/gradle/shadow.gradle"
+
+dependencies {
+ compile project(path: ":kudu-client", configuration: "shadow")
+ compile libs.yetusAnnotations
+
+ provided libs.scalaLibrary
+ provided libs.sparkCore
+ provided libs.sparkSql
+
+ testCompile project(path: ":kudu-client", configuration: "shadowTest")
+ testCompile libs.junit
+ testCompile libs.scalatest
+}
+
+// Add compatibility sources based on the spark version used.
+sourceSets {
+ main {
+ scala {
+ if (versions.sparkBase == "1") {
+ srcDir "src/main/spark1"
+ } else if (versions.sparkBase == "2") {
+ srcDir "src/main/spark2"
+ } else {
+ throw new GradleException("No compatibility sources exist for spark base version ${versions.sparkBase}")
+ }
+ }
+ }
+}
+
+// Adjust the artifact name to match the maven build.
+if (versions.sparkBase == "1") {
+ archivesBaseName = "kudu-spark_${versions.scalaBase}"
+} else {
+ archivesBaseName = "kudu-spark${versions.sparkBase}_${versions.scalaBase}"
+}
\ No newline at end of file
diff --git a/java/kudu-spark/pom.xml b/java/kudu-spark/pom.xml
index 703ff5a43f..7585940e84 100644
--- a/java/kudu-spark/pom.xml
+++ b/java/kudu-spark/pom.xml
@@ -101,6 +101,12 @@
${project.build.sourceEncoding}
${scala.version}
+
+
+ -feature
+
+ -Xlint
+
diff --git a/java/settings.gradle b/java/settings.gradle
new file mode 100644
index 0000000000..430e884bdc
--- /dev/null
+++ b/java/settings.gradle
@@ -0,0 +1,28 @@
+// 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 file contains the configuration of the project hierarchy.
+// Mainly we just define what subprojects are in the build.
+
+rootProject.name = "kudu-parent"
+include "kudu-client"
+include "kudu-client-tools"
+include "kudu-flume-sink"
+include "kudu-jepsen"
+include "kudu-mapreduce"
+include "kudu-spark"
+include "kudu-spark-tools"
---|