<?xml version="1.0"?>
<project name="wolfcrypt-jni"
         default="build"
         basedir="."
         xmlns:unless="ant:unless" >

    <description>
        wolfCrypt JNI is a Java wrapper for the wolfCrypt lightweight
        crypto library. wolfJCE is a JCE provider that wraps the wolfCrypt
        cryptography library.

        This build file requires JUnit for running provided JUnit tests.
        JUnit can be downloaded from: http:/www.junit.org/

        When running JUnit tests, this package will look for JUnit at:
        $JUNIT_HOME/junit.jar
    </description>

    <!-- versioning/manifest properties -->
    <property name="implementation.vendor"  value="wolfSSL Inc." />
    <property name="implementation.title"   value="wolfCrypt JNI" />
    <property name="implementation.version" value="1.8" />

    <!-- set properties for this build -->
    <property name="src.dir" value="src/main/java/" />
    <property name="jni.dir" value="jni/include/" />
    <property name="lib.dir" value="lib/" />
    <property name="build.dir" value="build" />
    <property name="doc.dir" value="docs/javadoc" />
    <property name="test.dir" value="src/test/java/" />
    <property name="test.build.dir" value="build/test" />
    <property name="reports.dir" value="build/reports" />
    <property name="examples.build.dir" value="examples/build" />
    <property name="examples.provider.dir" value="examples/provider" />
    <property name="examples.provider.build.dir" value="examples/build/provider" />

    <property name="junit4" value="junit-4.13.2.jar" />
    <property name="hamcrest-core" value="hamcrest-all-1.3.jar" />
    <property name="ant-junit4" value="ant/ant-junit4.jar" />
    <property name="jce.debug" value="false" />

    <!-- compatible defaults -->
    <property name="java.source" value="1.8" />
    <property name="java.target" value="1.8" />

    <!-- property file for code signing -->
    <property file="codeSigning.properties" />

    <property environment="env" />

    <!-- Detect if running on Windows host -->
    <condition property="isWindows">
        <os family="windows" />
    </condition>

    <!-- check if javac nativeheaderdir is available -->
    <condition property="have-nativeheaderdir">
        <and>
            <antversion atleast="1.9.8"/>
            <not>
                <or>
                    <equals arg1="${ant.java.version}" arg2="1.5"/>
                    <equals arg1="${ant.java.version}" arg2="1.6"/>
                    <equals arg1="${ant.java.version}" arg2="1.7"/>
                </or>
            </not>
        </and>
    </condition>

    <!-- classpath to compiled wolfcrypt-jni.jar, for running tests -->
    <path id="classpath">
        <fileset dir="${lib.dir}" includes="*.jar">
            <include name="wolfcrypt-jni.jar" />
        </fileset>
        <fileset dir="${env.JUNIT_HOME}">
            <include name="${junit4}" />
        </fileset>
    </path>

    <target name="clean">
        <delete dir="${test.build.dir}" />
        <delete dir="${build.dir}" />
        <delete dir="${examples.provider.build.dir}" />
        <delete dir="${examples.build.dir}" />
        <delete dir="${reports.dir}" />
        <delete failonerror="false">
            <fileset dir="${lib.dir}" includes="wolfcrypt-jni.jar" />
        </delete>
        <delete includeemptydirs="true" failonerror="false">
            <fileset dir="${doc.dir}" includes="**/*"/>
        </delete>
    </target>

    <!-- set javac flags: debug jar, no optimization, all debug symbols -->
    <target name="debug-javac-flags" if="jni.build.type.debug">
        <property name="java.debug" value="true" />
        <property name="java.debuglevel" value="source,lines,vars" />
        <property name="java.deprecation" value="true" />
        <property name="java.optimize" value="true" />
        <property name="java.source" value="${java.source}" />
        <property name="java.target" value="${java.target}" />
    </target>

    <!-- set javac flags: release, no debug, optimize -->
    <target name="release-javac-flags" if="jni.build.type.release">
        <property name="java.debug" value="false" />
        <property name="java.debuglevel" value="none" />
        <property name="java.deprecation" value="true" />
        <property name="java.optimize" value="true" />
        <property name="java.source" value="${java.source}" />
        <property name="java.target" value="${java.target}" />
    </target>

    <target name="init" depends="clean, debug-javac-flags, release-javac-flags">
        <mkdir dir="${build.dir}" />
        <mkdir dir="${lib.dir}" />
        <mkdir dir="${doc.dir}" />
        <mkdir dir="${test.build.dir}" />
        <mkdir dir="${reports.dir}" />
        <mkdir dir="${examples.provider.build.dir}" />
    </target>

    <!-- compile all JNI and JCE source files -->
    <target name="compile-nativeheaderdir" if="have-nativeheaderdir" depends="init">
        <javac
            srcdir="${src.dir}"
            destdir="${build.dir}"
            nativeheaderdir="${jni.dir}"
            debug="${java.debug}"
            debuglevel="${java.debuglevel}"
            deprecation="${java.deprecation}"
            optimize="${java.optimize}"
            source="${java.source}"
            target="${java.target}"
            classpathref="classpath"
            includeantruntime="false">
            <compilerarg value="-Xlint:-options" />
        </javac>
    </target>
    <target name="compile-javah" unless="have-nativeheaderdir" depends="init">
        <javac
            srcdir="${src.dir}"
            destdir="${build.dir}"
            debug="${java.debug}"
            debuglevel="${java.debuglevel}"
            deprecation="${java.deprecation}"
            optimize="${java.optimize}"
            source="${java.source}"
            target="${java.target}"
            classpathref="classpath"
            includeantruntime="false">
            <compilerarg value="-Xlint:-options" />
        </javac>
    </target>

    <!-- create JAR with ONLY JNI classes, not to be used with JCE -->
    <target name="jar-jni" depends="compile-nativeheaderdir, compile-javah">
        <jar jarfile="${lib.dir}/wolfcrypt-jni.jar">
            <manifest>
                <attribute name="Implementation-Title"
                           value="${implementation.title}" />
                <attribute name="Implementation-Version"
                           value="${implementation.version}" />
                <attribute name="Implementation-Vendor"
                           value="${implementation.vendor}" />
            </manifest>
            <fileset dir="${build.dir}">
                <include name="com/wolfssl/wolfcrypt/*.class"/>
            </fileset>
        </jar>
    </target>

    <!-- create JAR with JNI and JCE classes, use this when wanting JCE -->
    <target name="jar-jce" depends="compile-nativeheaderdir, compile-javah">
        <jar jarfile="${lib.dir}/wolfcrypt-jni.jar" basedir="${build.dir}">
            <manifest>
                <attribute name="Implementation-Title"
                           value="${implementation.title}" />
                <attribute name="Implementation-Version"
                           value="${implementation.version}" />
                <attribute name="Implementation-Vendor"
                           value="${implementation.vendor}" />
            </manifest>
        </jar>
        <echo unless:set="sign.alias">NOTICE: Skipping JAR signing, codeSigning.properties not found</echo>
    </target>

    <!-- sign jar, necessary for Oracle JDK -->
    <target name="sign" if="sign.alias" depends="jar-jce">
        <echo>Signing JAR with PRIMARY signature</echo>
        <signjar
            alias="${sign.alias}"
            keystore="${sign.keystore}"
            storepass="${sign.storepass}"
            tsaurl="${sign.tsaurl}" >
            <path>
                <fileset dir="${lib.dir}" includes="wolfcrypt-jni.jar" />
            </path>
        </signjar>
    </target>

    <!-- allow 2nd alternate signature, for legacy JCE deployments -->
    <target name="sign-alt" if="sign.alias2" depends="jar-jce">
        <echo>Signing JAR with SECONDARY signature</echo>
        <signjar
            alias="${sign.alias2}"
            keystore="${sign.keystore2}"
            storepass="${sign.storepass2}"
            tsaurl="${sign.tsaurl2}" >
            <path>
                <fileset dir="${lib.dir}" includes="wolfcrypt-jni.jar" />
            </path>
        </signjar>
    </target>

    <!-- detect if JNI class files have been compiled yet, set property -->
    <target name="jni-class-detect">
        <available file="${build.dir}/com/wolfssl/wolfcrypt/WolfCrypt.class"
                   property="jni.classes.present"/>
    </target>

    <!-- NOTE: depends on either jar-jni or jar-jce targets -->
    <target name="javah" if="jni.classes.present" unless="have-nativeheaderdir"
        depends="jni-class-detect"
        description="Generate javah headers">
        <javah destdir="${jni.dir}" force="yes" classpathref="classpath">
            <class name="com.wolfssl.wolfcrypt.WolfCrypt" />
            <class name="com.wolfssl.wolfcrypt.FeatureDetect" />
            <class name="com.wolfssl.wolfcrypt.Fips" />
            <class name="com.wolfssl.wolfcrypt.NativeStruct" />
            <class name="com.wolfssl.wolfcrypt.Aes" />
            <class name="com.wolfssl.wolfcrypt.Des3" />
            <class name="com.wolfssl.wolfcrypt.Logging" />
            <class name="com.wolfssl.wolfcrypt.Md5" />
            <class name="com.wolfssl.wolfcrypt.Sha" />
            <class name="com.wolfssl.wolfcrypt.Sha256" />
            <class name="com.wolfssl.wolfcrypt.Sha384" />
            <class name="com.wolfssl.wolfcrypt.Sha512" />
            <class name="com.wolfssl.wolfcrypt.Hmac" />
            <class name="com.wolfssl.wolfcrypt.Rng" />
            <class name="com.wolfssl.wolfcrypt.Rsa" />
            <class name="com.wolfssl.wolfcrypt.Dh" />
            <class name="com.wolfssl.wolfcrypt.Ecc" />
            <class name="com.wolfssl.wolfcrypt.Ed25519" />
            <class name="com.wolfssl.wolfcrypt.Curve25519" />
            <class name="com.wolfssl.wolfcrypt.Chacha" />
            <class name="com.wolfssl.wolfcrypt.WolfCryptError" />
            <class name="com.wolfssl.wolfcrypt.Asn" />
        </javah>
    </target>

    <target name="javadoc" description="Generate Javadocs">
        <javadoc sourcepath="${src.dir}" destdir="${doc.dir}" />
    </target>

    <target name="examples-jce" description="Build JCE Examples">
        <javac
            srcdir="${examples.provider.dir}"
            destdir="${examples.provider.build.dir}"
            debug="${java.debug}"
            debuglevel="${java.debuglevel}"
            deprecation="${java.deprecation}"
            optimize="${java.optimize}"
            source="${java.source}"
            target="${java.target}"
            classpathref="classpath"
            includeantruntime="false">
            <compilerarg value="-Xlint:-options"/>
        </javac>
    </target>

    <!-- compile JNI/JCE test classes, depending on how 'ant build' was run -->
    <target name="build-test" depends="set-build-debug, debug-javac-flags">

        <javac
            srcdir="${test.dir}"
            destdir="${test.build.dir}"
            debug="${java.debug}"
            debuglevel="${java.debuglevel}"
            deprecation="${java.depreciation}"
            optimize="${java.optimize}"
            source="${java.source}"
            target="${java.target}"
            classpathref="classpath"
            includeantruntime="false">
            <exclude name="com/wolfssl/provider/jce/test/**" unless="jar.includes.jce"/>
            <compilerarg value="-Xlint:-options" />
        </javac>

    </target>

    <!-- Set property to indicate Windows platform (Win32, x86) -->
    <target name="setup-win32-debug">
        <property name="ant.test.platform" value="Win32"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Debug/Win32/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/DLL Debug/Win32"/>
    </target>
    <target name="setup-win32-release">
        <property name="ant.test.platform" value="Win32"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Release/Win32/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/DLL Release/Win32"/>
    </target>

    <target name="setup-win64-debug">
        <property name="ant.test.platform" value="x64"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Debug/x64/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/DLL Debug/x64"/>
    </target>
    <target name="setup-win64-release">
        <property name="ant.test.platform" value="x64"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Release/x64/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/DLL Release/x64"/>
    </target>

    <target name="setup-win32-debug-fips">
        <property name="ant.test.platform" value="Win32"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Debug FIPS/Win32/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/IDE/WIN10/DLL Debug/Win32"/>
    </target>
    <target name="setup-win32-release-fips">
        <property name="ant.test.platform" value="Win32"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Release FIPS/Win32/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/IDE/WIN10/DLL Release/Win32"/>
    </target>
    <target name="setup-win64-debug-fips">
        <property name="ant.test.platform" value="x64"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Debug FIPS/x64/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/IDE/WIN10/DLL Debug/x64"/>
    </target>
    <target name="setup-win64-release-fips">
        <property name="ant.test.platform" value="x64"/>
        <property name="lib.win.dir" value="IDE/WIN/DLL Release FIPS/x64/"/>
        <property name="lib.wolfssl.win.dir" value="../wolfssl/IDE/WIN10/DLL Release/x64"/>
    </target>

    <!-- Windows ant test targets, should be used in place of 'ant test' -->
    <!-- Windows 32-bit -->
    <target name="test-win32-debug" depends="setup-win32-debug, test"
            description="Run JUnit tests on Windows x86/32-bit DLL Debug">
    </target>
    <target name="test-win32-release" depends="setup-win32-release, test"
            description="Run JUnit tests on Windows x86/32-bit DLL Release">
    </target>

    <!-- Windows x64 -->
    <target name="test-win64-debug" depends="setup-win64-debug, test"
            description="Run JUnit tests on Windows x64/64-bit DLL Debug">
    </target>
    <target name="test-win64-release" depends="setup-win64-release, test"
            description="Run JUnit tests on Windows x64/64-bit DLL Release">
    </target>

    <!-- Windows FIPS 140-2/140-3 -->
    <target name="test-win32-debug-fips" depends="setup-win32-debug-fips, test"
            description="Run JUnit tests on Windows x86/32-bit DLL FIPS Debug">
    </target>
    <target name="test-win32-release-fips" depends="setup-win32-release-fips, test"
            description="Run JUnit tests on Windows x86/32-bit DLL FIPS Release">
    </target>
    <target name="test-win64-debug-fips" depends="setup-win64-debug-fips, test"
            description="Run JUnit tests on Windows x64/64-bit DLL FIPS Debug">
    </target>
    <target name="test-win64-release-fips" depends="setup-win64-release-fips, test"
            description="Run JUnit tests on Windows x64/64-bit DLL FIPS Release">
    </target>

    <!-- Print usage if plain 'ant test' called on Windows -->
    <target name="antTestWindowsCheck">
      <condition property="antTestCalledIncorrect">
        <and>
          <equals arg1="${isWindows}" arg2="true"/>
          <equals arg1="${ant.project.invoked-targets}" arg2="test"/>
        </and>
      </condition>

      <fail message="Please see usage instructions below" if="antTestCalledIncorrect">
        wolfCrypt JNI and JCE: JUnit Test Usage on Windows
        ---------------------------------------------------------------------------->
        Run one of the following ant test targets for Windows use:
        Normal wolfSSL (non-FIPS):
            ant test-win32-debug         |  Run JUnit tests for Windows 32-bit Debug build
            ant test-win32-release       |  Run JUnit tests for Windows 32-bit Release build
            ant test-win64-debug         |  Run JUnit tests for Windows 64-bit Debug build
            ant test-win64-release       |  Run JUnit tests for Windows 64-bit Release build

        wolfSSL FIPS 140-2 / 140-3:
            ant test-win32-debug-fips    |  Run JUnit tests for Windows 32-bit Debug FIPS build
            ant test-win32-release-fips  |  Run JUnit tests for Windows 32-bit Release FIPS build
            ant test-win64-debug-fips    |  Run JUnit tests for Windows 64-bit Debug FIPS build
            ant test-win64-release-fips  |  Run JUnit tests for Windows 64-bit Release FIPS build
        ----------------------------------------------------------------------------
      </fail>
    </target>

    <!-- Primary ant test target, called direct on Linux/OSX
         or from test-win32/test-win64 on Windows -->
    <target name="test" description="Compile and run JUnit tests" depends="antTestWindowsCheck">

        <!-- detect if compiled JAR includes JCE or not -->
        <whichresource property="jar.includes.jce"
            class="com.wolfssl.provider.jce.WolfCryptProvider">
            <classpath>
                <path>
                    <fileset dir="${lib.dir}" includes="*.jar">
                        <include name="wolfcrypt-jni.jar" />
                    </fileset>
                </path>
            </classpath>
        </whichresource>

        <!-- delete and re-create test build directory -->
        <delete dir="${test.build.dir}" />
        <mkdir dir="${test.build.dir}" />
        <mkdir dir="${reports.dir}" />

        <!-- build classes of JUnit tests, if needed -->
        <antcall target="build-test"/>

        <echo unless:set="jar.includes.jce">NOTE: JCE classes not detected, only running JUnit tests for JNI</echo>

        <!-- run JUnit tests -->
        <junit printsummary="yes"
            showoutput="yes"
            haltonfailure="yes"
            fork="true">

            <jvmarg value="-Djava.library.path=$JAVA_HOME/bin${path.separator}${lib.dir}${path.separator}${lib.win.dir}${path.separator}${lib.wolfssl.win.dir}"/>

            <classpath>
                <pathelement location="${lib.dir}/wolfcrypt-jni.jar" />
                <pathelement location="${test.build.dir}" />
                <fileset dir="${env.JUNIT_HOME}">
                    <include name="${junit4}"/>
                    <include name="${hamcrest-core}"/>
                    <include name="${ant-junit4}"/>
                </fileset>
            </classpath>

            <formatter type="plain" />
            <formatter type="xml" />

            <sysproperty key="sun.boot.library.path" value="$JAVA_HOME/bin:${lib.dir}" />
            <sysproperty key="wolfjce.debug" value="${jce.debug}" />
            <env key="LD_LIBRARY_PATH" path="${env.LD_LIBRARY_PATH}:{lib.dir}:/usr/local/lib" />
            <env key="CLASSPATH" path="${env.LD_LIBRARY_PATH}:${env.JUNIT_HOME}/${junit4}" />

            <batchtest fork="yes" todir="${reports.dir}">
                <fileset dir="${test.dir}">
                    <!--<include name="**/*TestSuite.java" />-->
                    <include name="com/wolfssl/wolfcrypt/test/*TestSuite.java" />
                    <include name="com/wolfssl/wolfcrypt/test/fips/*TestSuite.java" />
                    <include if="jar.includes.jce" name="com/wolfssl/provider/jce/test/*TestSuite.java" />
                </fileset>
            </batchtest>

        </junit>
    </target>

    <!--<target name="build" depends="jar-jce, sign, sign-alt, javah, javadoc"-->
    <target name="build" description="Choice to build JNI or JCE">
        <echo>wolfCrypt JNI and JCE</echo>
        <echo>----------------------------------------------------------------------------</echo>
        <echo>USAGE:</echo>
        <echo>Run one of the following targets with ant:</echo>
        <echo>    build-jni-debug    |  builds debug JAR with only wolfCrypt JNI classes</echo>
        <echo>    build-jni-release  |  builds release JAR with only wolfCrypt JNI classes</echo>
        <echo>    build-jce-debug    |  builds debug JAR with JNI and JCE classes</echo>
        <echo>    build-jce-release  |  builds release JAR with JNI and JCE classes</echo>
        <echo>----------------------------------------------------------------------------</echo>
        <fail message="Please see usage instructions above."/>
    </target>

    <!-- set property to indicate DEBUG/RELEASE build -->
    <target name="set-build-debug">
        <property name="jni.build.type.debug" value="TRUE"/>
    </target>

    <target name="set-build-release">
        <property name="jni.build.type.release" value="TRUE"/>
    </target>

    <!-- main build targets -->
    <target name="build-jni-debug" depends="set-build-debug, jar-jni, javah, javadoc"
        description="Build library JAR (JNI classes ONLY)">
    </target>

    <target name="build-jni-release" depends="set-build-release, jar-jni, javah, javadoc"
        description="Build library JAR (JNI classes ONLY)">
    </target>

    <target name="build-jce-debug" depends="set-build-debug, jar-jce, sign, sign-alt, javah, javadoc, examples-jce"
        description="Build library JAR (JNI + JCE classes)">
    </target>

    <target name="build-jce-release" depends="set-build-release, jar-jce, sign, sign-alt, javah, javadoc, examples-jce"
        description="Build library JAR (JNI + JCE classes)">
    </target>

</project>

