/*
 * 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.
 */

plugins {
  id 'standard-subproject-configuration'
  id 'antlr'
  id 'geode-publish-java'
  id 'geode-pmd'
  id 'jmh'
  id 'javaVersions'
}

sourceSets {
  jca {
    compileClasspath += configurations.compileClasspath
    runtimeClasspath += configurations.runtimeClasspath
  }
}

idea {
  module {
    testSourceDirs += project.tasks.generateIntegrationTestGrammarSource.outputs.files
    testSourceDirs += project.tasks.generateDistributedTestGrammarSource.outputs.files
    testSourceDirs += project.tasks.generatePerformanceTestGrammarSource.outputs.files
    testSourceDirs += project.tasks.generateUpgradeTestGrammarSource.outputs.files
  }
}

def generatedResources = "$buildDir/generated-resources/main"

sourceSets {
  main {
    output.dir(generatedResources, builtBy: 'createVersionPropertiesFile')
  }
  test {
    output.dir(generatedResources, builtBy: 'createVersionPropertiesFile')
  }
}

sourceSets {
  // This works around resource-look up between integrationTest and test source-sets.
  // See GEODE-5803 / GEODE-5882
  test.resources.srcDirs.each { testResourceSrc ->
    integrationTest.resources.srcDir {
      testResourceSrc
    }
  }
}


// Creates the version properties file and writes it to the classes dir
tasks.register('createVersionPropertiesFile') {
  dependsOn rootProject.tasks.named('writeBuildInfo')

  def propertiesFile = file(generatedResources + "/org/apache/geode/internal/GemFireVersion.properties")
  def scmInfoFile = rootProject.tasks.writeBuildInfo.outputs.files

  inputs.files {
    scmInfoFile
  }
  outputs.files {
    propertiesFile
  }

  def props = [
    "Product-Name"      : productName,
    "Product-Version"   : version,
    "Build-Id"          : "${System.env.USER} ${buildId}".toString(),
    "Build-Platform"    : "${System.properties['os.name']} ${System.properties['os.version']} ${System.properties['os.arch']}".toString(),
    "Build-Java-Vendor" : System.properties['java.vendor'],
    "Build-Java-Version": System.properties['java.version']
  ] as Properties

  inputs.properties(props)

  doLast {
    def scmInfo = new Properties()
    new FileInputStream(scmInfoFile.singleFile).withStream { fis ->
      scmInfo.load(fis)
    }
    props.putAll(scmInfo)

    propertiesFile.getParentFile().mkdirs()
    new FileOutputStream(propertiesFile).withStream { fos ->
      props.store(fos, '')
    }
  }
}

ext.moduleName = group + '.core'

jar {

  from sourceSets.main.output
  from sourceSets.jca.output

  exclude 'org/apache/geode/internal/i18n/StringIdResourceBundle_ja.txt'
  exclude 'org/apache/geode/admin/doc-files/ds4_0.dtd'

  inputs.property("moduleName", moduleName)
  manifest {
    attributes('Automatic-Module-Name': moduleName)
  }

}

jar.dependsOn(createVersionPropertiesFile)

tasks.register('raJar', Jar) {
  dependsOn tasks.named('classes')
  description 'Assembles the jar archive that contains the JCA classes'
  from sourceSets.jca.output
  exclude 'org/apache/geode/ra/**'
  archiveFileName='ra.jar'
}

tasks.register('jcaJar', Jar) {
  dependsOn tasks.named('raJar')
  description 'Assembles the jar archive that contains the JCA bundle'
  archiveBaseName='geode-jca'
  archiveExtension='rar'
  metaInf { from 'src/jca/ra.xml' }
  from raJar.archivePath
}

configurations {
  //declaring new configuration that will be used to associate with artifacts
  archives

  classesOutput {
    extendsFrom api
    description 'a dependency that exposes the compiled classes'
  }

  jmh {
    extendsFrom testImplementation
  }

  raOutput
}

artifacts {
  raOutput raJar
}

dependencies {

  //These bom dependencies are used to constrain the versions of the dependencies listed below
  api(platform(project(':boms:geode-all-bom')))
  compileOnly(platform(project(':boms:geode-all-bom')))
  testCompileOnly(platform(project(':boms:geode-all-bom')))
  // As plugin configurations that do not extend from compile,
  // we must explicitly impose version constraints on these configurations.
  antlr platform(project(':boms:geode-all-bom'))
  jcaAnnotationProcessor(platform(project(':boms:geode-all-bom')))

  //A dependency that contains the compiled output of the source. What is this for?
  classesOutput sourceSets.main.output


  // Source Dependencies
  //------------------------------------------------------------

  //  The antlr configuration is used by the antlr plugin, which compiles grammar
  // files used by the query engine
  antlr 'antlr:antlr'

  // External
  //------------------------------------------------------------

  //Commons IO is used in persistence and management
  api('commons-io:commons-io')

  //tools.jar seems to be used by gfsh is some cases to control processes using
  //the sun attach API? But this code path may not even be used?
  compileOnly(files("${System.getProperty('java.home')}/../lib/tools.jar"))

  //Find bugs is used in multiple places in the code to suppress findbugs warnings
  compileOnly('com.github.stephenc.findbugs:findbugs-annotations')
  testCompileOnly('com.github.stephenc.findbugs:findbugs-annotations')

  //Spring web is used for SerializableObjectHttpMessageConverter
  compileOnly('org.springframework:spring-web')

  // find bugs leaks in from spring, needed to remove warnings.
  compileOnly('com.google.code.findbugs:jsr305')

  compileOnly('org.jetbrains:annotations')

  //Jgroups is a core component of our membership system.
  implementation('org.jgroups:jgroups')

  //Antlr is used by the query engine.
  implementation('antlr:antlr')

  //Jackson annotations is used in gfsh
  implementation('com.fasterxml.jackson.core:jackson-annotations')

  //Jackson databind is used in gfsh, and also in pdx
  implementation('com.fasterxml.jackson.core:jackson-databind')

  //Commons validator is used to validate inet addresses in membership
  implementation('commons-validator:commons-validator')


  //jaxb is used by cluster configuration
  implementation('javax.xml.bind:jaxb-api')

  //jaxb is used by cluster configuration
  runtimeOnly('com.sun.xml.bind:jaxb-impl')
  runtimeOnly('com.sun.activation:javax.activation')

  //istack appears to be used only by jaxb, not in our code. jaxb doesn't
  //declare this as required dependency though. It's unclear if this is needed
  //Runtime
  runtimeOnly('com.sun.istack:istack-commons-runtime') {
    exclude group: '*'
  }

  runtimeOnly(project(':geode-deployment:geode-deployment-legacy'))

  //Commons lang is used in many different places in core
  implementation('org.apache.commons:commons-lang3')

  //Commons modeler is used by the (deprecated) admin API
  compileOnly('commons-modeler:commons-modeler') {
    exclude module: 'commons-logging-api'
    exclude module: 'mx4j-jmx'
    exclude module: 'xml-apis'
    ext.optional = true
  }

  //micrometer is used for micrometer based metrics from geode geode
  api('io.micrometer:micrometer-core')


  //FastUtil contains optimized collections that are used in multiple places in core
  implementation('it.unimi.dsi:fastutil')

  //Mail API is used by the deprecated admin API
  compileOnly('javax.mail:javax.mail-api') {
    ext.optional = true
  }

  //The resource-API is used by the JCA support.
  api('javax.resource:javax.resource-api')


  //MX4J is used by the old admin API
  compileOnly('mx4j:mx4j') {
    ext.optional = true
  }

  //MX4J remote is used by the old admin API
  compileOnly('mx4j:mx4j-remote') {
    ext.optional = true
  }

  //MX4J tools is used by the old admin API
  compileOnly('mx4j:mx4j-tools') {
    ext.optional = true
  }

  //JNA is used for locking memory and preallocating disk files.
  implementation('net.java.dev.jna:jna')
  implementation('net.java.dev.jna:jna-platform')

  //JOptSimple is used by gfsh. A couple of usages have leaked into DiskStore
  implementation('net.sf.jopt-simple:jopt-simple')

  //Log4j is used everywhere
  implementation('org.apache.logging.log4j:log4j-api')


  implementation('io.swagger.core.v3:swagger-annotations') {
    ext.optional = true
  }

  runtimeOnly(project(':geode-http-service')) {
    ext.optional = true
  }

  //Snappy is used for compressing values, if enabled
  implementation('org.iq80.snappy:snappy') {
    ext.optional = true
  }

  //Shiro is used for security checks throughout geode-core
  //API - Shiro is exposed in geode's ResourcePermission class
  api('org.apache.shiro:shiro-core')

  //Classgraph is used by the gfsh cli, and also for function deployment (which happens in a server
  //in response to a gfsh command)
  implementation('io.github.classgraph:classgraph')

  //RMIIO is used for uploading jar files and copying them between locator an servers
  implementation('com.healthmarketscience.rmiio:rmiio')

  //Geode-common has annotations and other pieces used geode-core
  api(project(':geode-common'))
  implementation(project(':geode-logging'))
  implementation(project(':geode-membership'))
  implementation(project(':geode-unsafe'))
  api(project(':geode-serialization'))
  implementation(project(':geode-tcp-server'))

  //geode-management currently has pieces of the public API
  //copied into it, so it is an API dependency
  api(project(':geode-management'))


  jcaImplementation(sourceSets.main.output)

  testImplementation(project(':geode-junit')) {
    exclude module: 'geode-core'
  }
  testImplementation(project(':geode-concurrency-test'))
  testImplementation(project(':geode-serialization'))
  testImplementation('org.apache.bcel:bcel')
  testImplementation('org.assertj:assertj-core')
  testImplementation('org.mockito:mockito-core')
  testImplementation('org.mockito:mockito-junit-jupiter')
  testImplementation('com.pholser:junit-quickcheck-core')
  testImplementation('pl.pragmatists:JUnitParams')
  testImplementation('com.tngtech.archunit:archunit-junit4')
  testImplementation(project(path: ':geode-core', configuration: 'raOutput'))
  testImplementation('org.springframework:spring-web')
  testImplementation(files("${System.getProperty('java.home')}/../lib/tools.jar"))
  testImplementation('org.junit-pioneer:junit-pioneer')

  testCompileOnly('org.jetbrains:annotations')

  testRuntimeOnly('commons-collections:commons-collections')
  testRuntimeOnly('commons-configuration:commons-configuration')
  testRuntimeOnly('commons-io:commons-io')
  testRuntimeOnly('commons-validator:commons-validator')
  testRuntimeOnly('com.pholser:junit-quickcheck-generators')

  // Needed for JDK8, not JDK11, after nebula.facet v7.0.9
  integrationTestImplementation(files("${System.getProperty('java.home')}/../lib/tools.jar"))
  integrationTestImplementation(project(':geode-gfsh'))
  integrationTestImplementation(project(':geode-junit'))
  integrationTestImplementation(project(':geode-dunit'))
  integrationTestImplementation(project(':geode-log4j'))
  integrationTestImplementation(project(':geode-concurrency-test'))
  integrationTestImplementation(project(':geode-serialization'))
  integrationTestImplementation('org.apache.bcel:bcel')
  integrationTestImplementation('org.apache.logging.log4j:log4j-core')
  integrationTestImplementation('pl.pragmatists:JUnitParams')
  integrationTestImplementation('com.tngtech.archunit:archunit-junit4')
  integrationTestImplementation('org.junit-pioneer:junit-pioneer')

  integrationTestRuntimeOnly('org.apache.derby:derby')
  integrationTestRuntimeOnly('xerces:xercesImpl')
  integrationTestRuntimeOnly('com.fasterxml.jackson.datatype:jackson-datatype-jsr310')

  // The block below is only for the deprecated admin mbeans API
  integrationTestRuntimeOnly('commons-modeler:commons-modeler')
  integrationTestRuntimeOnly('org.springframework:spring-web')
  integrationTestRuntimeOnly('javax.mail:javax.mail-api')
  integrationTestRuntimeOnly('mx4j:mx4j')
  integrationTestRuntimeOnly('mx4j:mx4j-remote')
  integrationTestRuntimeOnly('mx4j:mx4j-tools')
  // End deprecated requirements


  distributedTestImplementation(project(':geode-gfsh'))
  distributedTestImplementation(project(':geode-wan'))
  distributedTestImplementation(project(':geode-junit')) {
    exclude module: 'geode-core'
  }
  distributedTestImplementation(project(':geode-dunit')) {
    exclude module: 'geode-core'
  }
  distributedTestImplementation(project(':geode-log4j')) {
    exclude module: 'geode-core'
  }
  distributedTestImplementation('pl.pragmatists:JUnitParams')
  distributedTestImplementation('com.jayway.jsonpath:json-path-assert')

  distributedTestRuntimeOnly('org.apache.derby:derby')


  upgradeTestImplementation(project(':geode-dunit')) {
    exclude module: 'geode-core'
  }

  upgradeTestRuntimeOnly(project(path: ':geode-old-versions', configuration: 'classpathsOutput'))
  upgradeTestRuntimeOnly(project(':geode-log4j'))
  upgradeTestRuntimeOnly(project(':geode-old-client-support'))

  performanceTestImplementation(project(':geode-junit')) {
    exclude module: 'geode-core'
  }
  performanceTestImplementation(project(':geode-log4j'))

  jmhImplementation('org.jctools:jctools-core')
}

tasks.eclipse.dependsOn(generateGrammarSource)

distributedTest {
  // Some tests have inner tests that should be ignored
  exclude "**/*\$*.class"
}

configure([
  upgradeTest,
  repeatUpgradeTest
]) {
  dependsOn(':geode-assembly:installDist')

  environment "JAVA_HOME_8u265", javaHomeForVersion(it, "jdk8u265", "8u265+1")
  environment "JAVA_HOME_8u272", javaHomeForVersion(it, "jdk8u272", "8u272+10")
  environment 'GEODE_HOME', "$buildDir/../../geode-assembly/build/install/apache-geode"
}

rootProject.generate.dependsOn(generateGrammarSource)

tasks.named('processIntegrationTestResources') {
  duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.EXCLUDE
}
