################################################################################
#
# java.cygclass - functions for creating GNU Classpath based Java packages
#
# Part of cygport - Cygwin packaging application
# Copyright (C) 2006-2016 Yaakov Selkowitz
# Provided by the Cygwin Ports project <http://sourceware.org/cygwinports/>
#
# cygport is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cygport is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cygport.  If not, see <http://www.gnu.org/licenses/>.
#
################################################################################

#****h* Cygclasses/java.cygclass
#  SYNOPSIS
#  inherit java
#  DESCRIPTION
#  GNU Classpath provides an open-source implementation of a Java runtime
#  which is mostly compatibly with JDK 1.5.  Driven by a compatible Java
#  Virtual Machine, its runtime and tools together with the OpenJDK and Eclipse
#  compiler tools provide a Java environment which can build and run a wide
#  variety of Java programs.
#
#  This cygclass provides definitions and functions for building packages
#  which use the GNU Classpath Java environment.
#  INHERITED BY
#  ant.cygclass
#  REQUIRES
#  gij/jamvm, ecj/jdk6-langtools/classpath-tools, fastjar, gcc4-java.
#****

#****d* java.cygclass/JAR
#  DESCRIPTION
#  Absolute path to a 'jar' de/compression tool, provided by fastjar or gjar.
#****
JAR=/usr/bin/jar

#****d* java.cygclass/JAVA
#  DESCRIPTION
#  Absolute path to a Java interpreter, provided by jamvm or gij-4.
#****
JAVA=/usr/bin/java

#****d* java.cygclass/JAVAC
#  DESCRIPTION
#  Absolute path to a Java compiler, provided by javac or ecj.
#****
JAVAC=/usr/bin/javac

#****d* java.cygclass/JAVADOC
#  DESCRIPTION
#  Absolute path to a Java API documentation generator, provided by javadoc or gjdoc.
#****
JAVADOC=/usr/bin/javadoc

#****d* java.cygclass/JAVAH
#  DESCRIPTION
#  Absolute path to a JNI header generator, provided by javah or gjavah.
#****
JAVAH=/usr/bin/javah

#****d* java.cygclass/JAVA_HOME
#  DESCRIPTION
#  Prefix of the Java installation.
#****
JAVA_HOME=/usr

#****d* java.cygclass/JAVA_DIR
#  DESCRIPTION
#  Installation path for Java .jar files.
#****
JAVA_DIR=/usr/share/java

#****d* java.cygclass/JAVADOC_DIR
#  DESCRIPTION
#  Installation path for Javadoc API documentation.
#****
JAVADOC_DIR=/usr/share/javadoc

__java_fixup_cp() {
	local inpath outpath

	for inpath in ${1//:/ }
	do
		case $inpath in
			*/*)	;;
			*.jar)	inpath=${JAVA_DIR}/${inpath} ;;
			*)		;;
		esac
		if [ ! -e ${inpath} ] && [ ! -e ${D}${inpath} ]
		then
			warning "CLASSPATH: ${inpath} not found"
		fi
		outpath+=${inpath}:
	done

	echo -n ${outpath%:}
}

#****v* java.cygclass/JAVA_CLASSPATH
#  DESCRIPTION
#  A colon-separated list of directories and .jar files to pass to Java's
#  CLASSPATH environment variable.  Any .jar files which are listed by
#  basename only are assumed to be installed in JAVA_DIR.
#  NOTE
#  The user CLASSPATH variable is ignored so as to prevent interference
#  from a native Windows installation of Java.
#****

# prevent Win32 Java interference
unset CLASSPATH

if defined JAVA_CLASSPATH
then
	export CLASSPATH=$(__java_fixup_cp ${JAVA_CLASSPATH})
fi

case ${PN} in
	java-*)	ORIG_PN=${ORIG_PN:-${PN#java-}} ;;
esac

#****C* java.cygclass/cygjar
#  SYNOPSIS
#  cygjar OPTIONS JAR_FILE [MANIFEST_FILE] [-C DIRECTORY] [FILES] ...
#  DESCRIPTION
#  Runs the JAR command with the provided options, catching any errors if
#  they occur.  Please see the JAR --help text for a complete list of options.
#****
cygjar() {
	verbose ${JAR} ${@} || error "cygjar: command failed"
}

#****f* java.cygclass/cygjava
#  SYNOPSIS
#  cygjava [-jar JAR_FILE] [-classpath CLASSPATH] [OPTIONS] CLASS [ARGUMENTS]
#  DESCRIPTION
#  Runs the JAVA command with the provided options, catching any errors if
#  they occur.  Please see the JAVA -help text for a complete list of options.
#****
cygjava() {
	verbose ${JAVA} ${@} || error "cygjava: execution failed"
}

#****C* java.cygclass/cygjavac
#  SYNOPSIS
#  cygjavac [-classpath CLASSPATH] [OPTIONS] SOURCE_FILES|DIRECTORIES
#  DESCRIPTION
#  Runs the JAVAC command with the provided options, catching any errors if
#  they occur.  Please see the JAVAC -help text for a complete list of options.
#****
cygjavac() {
	verbose ${JAVAC} ${@} || error "cygjavac: compile failed"
	# warning/error messages may not end with a newline
	echo
}

#****C* java.cygclass/cygjavadoc
#  SYNOPSIS
#  cygjavadoc [OPTIONS] [-d OUTPUT_PATH] PACKAGES
#  DESCRIPTION
#  Runs the JAVADOC command with the provided options, catching any errors if
#  they occur.  Please see the JAVADOC -help text for a complete list of options.
#****
cygjavadoc() {
	# TODO: add -link file://${JAVADOC_DIR}/classpath, make links relative
	verbose ${JAVADOC} ${@} || error "cygjavadoc: generation failed"
}

#****C* java.cygclass/cygjavah
#  SYNOPSIS
#  cygjavah [-classpath CLASSPATH] [-d OUTPUT_PATH] [-jni] CLASSES
#  DESCRIPTION
#  Runs the JAVAH command with the provided options, catching any errors if
#  they occur.  Please see the JAVAH -help text for a complete list of options.
#****
cygjavah() {
	verbose ${JAVAH} ${@} || error "cygjavah: generation failed"
}

#****T* java.cygclass/cygjunit
#  SYNOPSIS
#  cygjunit [-classpath CLASSPATH] CLASSES
#  DESCRIPTION
#  Runs the JUnit tests defined in the given class(es).
#****
cygjunit() {
	local junitcp=${JAVA_DIR}/junit.jar

	case ${1} in
		-classpath) junitcp+=:${2} ; shift 2 ;;
	esac

	for jtest in ${@}
	do
		echo $jtest:
		${JAVA} -Djava.awt.headless=true -classpath ${CLASSPATH}:${junitcp}:. junit.textui.TestRunner $jtest
	done
}

#****I* java.cygclass/dojar
#  SYNOPSIS
#  dojar JAR_FILES
#  DESCRIPTION
#  Installs the given .jar files into JAVA_DIR under $D.  If the name of the
#  .jar includes a version number, an unversioned symlink is created alongside
#  the .jar file.
#****
dojar() {
	dodir ${JAVA_DIR}

	for i
	do
		if [ ! -e ${i} ]
		then
			error "dojar: ${i}: file not found"
		fi

		__doinstall 0644 ${i} ${JAVA_DIR} || error "dojar ${i} failed"
		ib=${i##*/}
		case ${ib} in
			*-[0-9]*.jar)
				dosym ${ib} ${JAVA_DIR}/${ib%%-[0-9]*}.jar
				;;
		esac
	done
}

#****I* java.cygclass/newjar
#  SYNOPSIS
#  newjar JAR_FILE NEW_JAR_FILE_NAME
#  DESCRIPTION
#  Installs the given .jar file into JAVA_DIR under $D, renaming it per the
#  second argument.  If the new name of the .jar includes a version number,
#  an unversioned symlink is created alongside the .jar file.
#****
newjar() {
	if (( $# != 2 ))
	then
		error "newjar: requires exactly two arguments"
	fi

	dodir ${JAVA_DIR}

	if [ ! -e ${1} ]
	then
		error "newjar: ${1}: file not found"
	fi

	__doinstall 0644 ${1} ${JAVA_DIR}/${2} || error "newjar: install ${1} failed"
	ib=${2##*/}
	case ${ib} in
		*-[0-9]*.jar)
			dosym ${ib} ${JAVA_DIR}/${ib%%-[0-9]*}.jar
			;;
	esac
}

#****I* java.cygclass/dojavadoc
#  SYNOPSIS
#  dojavadoc DIRECTORY
#  DESCRIPTION
#  Installs the Javadoc documentation in the given directory into a subdirectory
#  of JAVADOC_DIR based on the name of the package.
#****
dojavadoc() {
	local pkgdocdir=${JAVADOC_DIR}/${PN#java-}

	if (( $# != 1 ))
	then
		error "dojavadoc: requires exactly one argument"
	fi

	if [ ! -d ${1} ]
	then
		error "dojavadoc: ${1}: file not found"
	fi

	if [ ! -e ${1}/package-list ]
	then
		error "dojavadoc: ${1}: no package-list, not a javadoc directory"
	fi

	dodir ${pkgdocdir}

	cp -Lr ${1}/* ${D}${pkgdocdir}/ || error "dojavadoc ${1} failed"
	# FIXME: make links to file://${JAVADOC_DIR}/ relative
}


#****I* java.cygclass/newjavadoc
#  SYNOPSIS
#  newjavadoc DIRECTORY DESTINATION_SUBDIR
#  DESCRIPTION
#  Installs the Javadoc documentation in the given directory into a subdirectory
#  of JAVADOC_DIR based on DESTINATION_SUBDIR.  This is useful if a package
#  builds more than one set of Javadocs.
#****
newjavadoc() {
	local pkgdocdir=${JAVADOC_DIR}/${2}

	if (( $# != 2 ))
	then
		error "newjavadoc: requires exactly two arguments"
	fi

	if [ ! -d ${1} ]
	then
		error "newjavadoc: ${1}: file not found"
	fi

	if [ ! -e ${1}/package-list ]
	then
		error "newjavadoc: ${1}: no package-list, not a javadoc directory"
	fi

	dodir ${pkgdocdir}

	cp -Lr ${1}/* ${D}${pkgdocdir}/ || error "newjavadoc ${1} failed"
	# FIXME: make links to file://${JAVADOC_DIR}/ relative
}

#****I* java.cygclass/java_wrapper
#  SYNOPSIS
#  java_wrapper [JAVA_OPTIONS] WRAPPER_NAME JAR_FILE [MAIN_CLASS]
#  DESCRIPTION
#  Creates a wrapper script for the given .jar file.  If the .jar file is
#  installed into JAVA_DIR, its basename can be used instead of a path.
#  If the jar file manifest defines a Main-Class, then the third argument
#  (the class providing the main() function) can be omitted.
#
#  Options to be passed to the JAVA runtime (rather than the Java
#  program) can be added before the wrapper name.  These arguments must
#  begin with a hyphen.
#****
java_wrapper() {
	local jargs jwrapper jar jarmain jmain jcmdopt

	if (( $# < 2 ))
	then
		error "java_wrapper requires at least two arguments"
	fi

	while true
	do
		case ${1} in
			-*)	jargs+="${1} " ; shift ;;
			*)	break ;;
		esac
	done

	jwrapper=${1}
	jar=$(__java_fixup_cp ${2})
	jmain=${3}

	if ! defined jmain
	then
		case ${jar} in
		*:*)  error "java_wrapper: a Main-Class must be specified with multiple Jars" ;;
		esac

		check_prog_req unzip
		jarmain=$(unzip -c ${D}${jar} META-INF/MANIFEST.MF 2>/dev/null | grep ^Main-Class: | cut -d' ' -f2-)
		jmain=${jarmain}

		if ! defined jarmain
		then
			error "java_wrapper: ${jar##*/} does not contain a Main-Class"
		fi
	fi

	# Per java(1): "[-jar] When you use this option, the JAR file is the source
	# of all user classes, and other user class path settings are ignored."
	if defined jarmain && ! defined CLASSPATH
	then
		jcmdopt="-jar ${jar}"
		jmain=
	else
		jcmdopt="-classpath ${jar}:${CLASSPATH}:\$CLASSPATH:."
	fi

	dodir /usr/bin

	echo -e "#!/bin/sh\nexec ${JAVA} ${jargs} ${jcmdopt} ${jmain} \"\$@\"" > ${D}/usr/bin/${jwrapper}
	chmod +x ${D}/usr/bin/${jwrapper}
}

readonly -f __java_fixup_cp cygjar cygjava cygjavac cygjavadoc cygjavah \
            dojar newjar dojavadoc newjavadoc java_wrapper
