Apache Ant/Creating a .xar file

Motivation edit

This example is under development!

You want to create an XML archive file (.xar file) directly from your source code that can be used to load library modules or applications into a native XML database. This makes it much easier for users to install your module or application. The packaging process does all the work of uploading your files into the correct location on a running eXist server and also sets all the permissions of the XQuery files (.xq) for you automatically.

Method edit

We need to create a "zip" file with all the right components in it.

The format of the package is here:

http://expath.org/spec/pkg

The eXist-specific package documentation is here:

http://demo.exist-db.org/exist/apps/doc/repo.xml

GUI Package vs. On-Disk Library vs. In DB Library edit

There are three types of installation packages:

  1. A external library that is not in the database
  2. A library that is loaded into the database
  3. A full application with a GUI

For all library apps without GUI but deployed into db you must use two attributes, one for the target the type="library" use the following structure:

 target="some /db path" + type="library"

For a simple XQuery library package, which only needs to be registered with eXist but not deployed within the exist database the target attribute should not be used.

 no target + type="library"

Sample Package Structure edit

The archive must contain two XML descriptor files in the root directory: expath-pkg.xml and repo.xml

Sample expath-pkg.xml file

<package xmlns="http://expath.org/ns/pkg" name="http://example.com/apps/myapp" 
         abbrev="myapp" version="0.1" spec="1.0">
    <title>My Cool Application</title>
    <dependency package="http://exist-db.org/apps/xsltforms"/>
</package>

Note that the file name and the string in the namespace are "pkg" but the element name and the attribute in the dependency are "package". Make sure to keep these clear.

The format of this XML file is describe in the EXPath documentation.

Sample repo.xml file that contains instructions for the eXist-specific packaging

<meta xmlns="http://exist-db.org/xquery/repo">
    <description>My eXist application</description>
    <author>Dan McCreary</author>
    <website>http://danmccreary.com</website>
    <status>alpha</status>
    <license>GNU-LGPL</license>
    <copyright>true</copyright>
    <!-- set this to "application" (without quotes) for system that have a GUI -->
    <type>application</type>
    <target>myapp</target>
    <prepare>pre-install.xql</prepare>
    <finish>post-install.xql</finish>
    <permissions user="admin" password="" group="dba" mode="rw-rw-r--"/>
    <!-- this element is automatically added by the deployment tool -->
    <deployed>2012-11-28T23:15:39.646+01:00</deployed>
</meta>

Sample Apache Ant Target to Generate an Application .xar file edit

This ant target needs the following inputs:

 source-dir - the place you keep your source code
 package-dir - a temp dir such as /tmp/my-package to store temporary files
 app-name - the name of your application
 app-version - the version of your application
  1. verify that repo.xml and expath-package.xml exist in the source dir and copy them into temp.dir
  2. copy all application files temp.dir
  3. create zip file from contents of temp.dir in the packages area and upload it to repositories if needed
<target name="generate-app-xar" description="Generate Application xar archive file">
   <echo>Making Package for ${app-name} use source from ${source-dir}</echo>
   <zip destfile="${package-dir}/${app-name}-${app-version}.xar">
         <fileset dir="${source-dir}">
            <include name="**/*.*" />
            <exclude name="**/.svn" />
      </fileset>
   </zip>
   <echo>Package is stored at ${package-dir}/${app-name}-${app-version}.xar</echo>
</target>

Sample Apache Ant Target to Generate a Library .xar file edit

This script depends on the following Ant properties:

 ant.project.name - the name of the project
 xslt.dir - the directory that the XSLT script are stored
 temp.dir - a temp dir such as /tmp to store temporary files
 web.specs.dir - the place to put the results
<target name="generate-xar" description="Generate xar archive">
        <echo>Making ${ant.project.name}.xar...</echo>

        <!-- run a transform in the input specification file to create the a.xml file -->
        <xslt force="true" style="${xslt.dir}/generate-xar-descriptors.xsl" 
              in="${web.specs.dir}/${ant.project.name}/${ant.project.name}.xml" 
              out="${temp.dir}/files/a.xml">
            <param name="module-version" expression="${module-version}" />
            <param name="eXist-main-class-name" expression="${eXist-main-class-name}" />
        </xslt>
        <delete file="${temp.dir}/files/a.xml" />
        
        <!-- now create the .xar file with all our files in the right place -->
        <zip destfile="${temp.dir}/archives/${ant.project.name}-${module-version}.xar">
            <fileset dir="${temp.dir}/files">
                <include name="**/*.*" />
                <exclude name="*-tests.jar" />
            </fileset>
        </zip>
    </target>

Sample XSLT Script edit

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">

	<xsl:output method="xml" />

	<xsl:param name="module-version" />
	<xsl:param name="eXist-main-class-name" />

	<xsl:template match="/">
		<xsl:variable name="module-namespace">
			<xsl:copy-of select="//element()[@id = 'module-namespace']" />
		</xsl:variable>
		<xsl:variable name="module-prefix">
			<xsl:copy-of select="//element()[@id = 'module-prefix']" />
		</xsl:variable>
		<xsl:variable name="spec-title">
			<xsl:copy-of select="concat('EXPath ', //element()[local-name() = 'title'])" />
		</xsl:variable>
		<xsl:variable name="author">
			<xsl:copy-of select="//element()[local-name() = 'author'][1]/element()[1]" />
		</xsl:variable>

		<xsl:result-document href="target/files/expath-pkg.xml">
			<package xmlns="http://expath.org/ns/pkg" name="http://expath.org/lib/{$module-prefix}" abbrev="{concat('expath-', $module-prefix)}"
				version="{$module-version}" spec="1.0">
				<title>
					<xsl:value-of select="$spec-title" />
				</title>
				<dependency processor="http://exist-db.org/" />
			</package>
		</xsl:result-document>

		<xsl:result-document href="target/files/repo.xml">
			<meta xmlns="http://exist-db.org/xquery/repo">
				<description>
					<xsl:value-of select="$spec-title" />
				</description>
				<author>
					<xsl:value-of select="$author" />
				</author>
				<website />
				<status>stable</status>
				<license>GNU-LGPL</license>
				<copyright>true</copyright>
				<type>library</type>
			</meta>
		</xsl:result-document>

		<xsl:result-document href="target/files/exist.xml">
			<package xmlns="http://exist-db.org/ns/expath-pkg">
				<jar>
					<xsl:value-of select="concat('expath-', $module-prefix, '.jar')" />
				</jar>
				<java>
					<namespace>
						<xsl:value-of select="$module-namespace" />
					</namespace>
					<class>
						<xsl:value-of select="concat('org.expath.exist.', $eXist-main-class-name)" />
					</class>
				</java>
			</package>
		</xsl:result-document>

		<xsl:result-document href="target/files/cxan.xml">
			<package xmlns="http://cxan.org/ns/package" id="{concat('expath-', $module-prefix, '-exist')}" name="http://expath.org/lib/{$module-prefix}"
				version="{$module-version}">
				<author id="{$author/element()/@id}">
					<xsl:value-of select="$author" />
				</author>
				<category id="libs">Libraries</category>
				<category id="exist">eXist extensions</category>
				<tag>
					<xsl:value-of select="$module-prefix" />
				</tag>
				<tag>expath</tag>
				<tag>library</tag>
				<tag>exist</tag>
			</package>
		</xsl:result-document>

	</xsl:template>
</xsl:stylesheet>

Sample XQuery Script edit

Acknowledgements edit

The Apache Ant target and the XSLT script were provided by Claudius Teodorescu.