Difference between revisions of "Repository"

From BaseX Documentation
Jump to navigation Jump to search
(32 intermediate revisions by the same user not shown)
Line 5: Line 5:
 
=Introduction=
 
=Introduction=
  
One of the reasons why languages such as Java or Perl have been so successful is the vast amount of libraries that are available to developers.
+
One of the things that makes languages successful is the availability of external libraries. As XQuery comes with only 150 pre-defined functions, which cannot meet all requirements, additional library modules exist – such as [http://www.functx.com/ FunctX] – which extend the language with new features.
As XQuery comes with only 150 pre-defined functions, which cannot meet all requirements, there is some need for additional library modules – such as [http://www.functx.com/ FunctX] – that extend the language with new features.
 
  
BaseX offers the following mechanisms to make modules accessible to the XQuery processor:
+
BaseX offers the following mechanisms to make external modules accessible to the XQuery processor:
  
# The default [[#Packaging|Packaging]] mechanism will install single XQuery and Java modules in the repository.
+
# The internal [[#Packaging|Packaging]] mechanism will install single XQuery and JAR modules in the repository.
 
# The [[#EXPath Packaging|EXPath Packaging]] system provides a generic mechanism for adding XQuery modules to query processors. A package is defined as a {{Code|.xar}} archive, which encapsulates one or more extension libraries.
 
# The [[#EXPath Packaging|EXPath Packaging]] system provides a generic mechanism for adding XQuery modules to query processors. A package is defined as a {{Code|.xar}} archive, which encapsulates one or more extension libraries.
  
=Accessing Modules=
+
==Accessing Modules==
  
Library modules can be imported with the {{Code|import module}} statement,
+
Library modules can be imported with the {{Code|import module}} statement, followed by a freely choosable prefix and the namespace of the target module. The specified location may be absolute or relative; in the latter case, it is resolved against the location (i.e., ''static base URI'') of the calling module. Import module statements must be placed at the beginning of a module:
followed by a freely choosable prefix and the namespace of the target module.
 
The specified location may be absolute or relative; in the latter case, it is resolved
 
against the location (i.e., ''static base URI'') of the calling module.
 
Import module statements must be placed at the beginning of a module:
 
  
'''Main Module''' <code>[http://files.basex.org/modules/org/basex/modules/Hello/HelloUniverse.xq HelloUniverse.xq]</code>:
+
'''Main Module''' <code>hello-universe.xq</code>:
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
import module namespace m = 'http://basex.org/modules/Hello' at 'HelloWorld.xqm';
+
import module namespace m = 'http://basex.org/modules/hello' at 'hello-world.xqm';
 
m:hello("Universe")
 
m:hello("Universe")
</pre>
+
</syntaxhighlight>
  
'''Library Module''' <code>[http://files.basex.org/modules/org/basex/modules/Hello/HelloWorld.xqm HelloWorld.xqm]</code> (in the same directory):
+
'''Library Module''' <code>hello-world.xqm</code> (in the same directory):
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
 
module namespace m = 'http://basex.org/modules/Hello';
 
module namespace m = 'http://basex.org/modules/Hello';
 
declare function m:hello($world) {
 
declare function m:hello($world) {
 
   'Hello ' || $world
 
   'Hello ' || $world
 
};
 
};
</pre>
+
</syntaxhighlight>
  
Repository modules are stored in a directory named {{Code|BaseXRepo}} or {{Code|repo}}, which resides in your [[Configuration#Home Directory|home directory]]. XQuery modules can be manually copied to the repository directory or installed and deleted via [[#Commands|commands]].
+
If no location is supplied, modules will be looked up in the repository. Repository modules are stored in the {{Code|repo}} directory, which resides in your [[Configuration#Home Directory|home directory]]. XQuery modules can be manually copied to the repository directory or installed and deleted via [[#Commands|commands]].
  
If a module has been placed in the repository (see below), there is no need to specify the location. The following example calls a function from the FunctX module:
+
The following example calls a function from the FunctX module in the repository:
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
 
import module namespace functx = 'http://www.functx.com';
 
import module namespace functx = 'http://www.functx.com';
 
functx:capitalize-first('test')
 
functx:capitalize-first('test')
</pre>
+
</syntaxhighlight>
  
 
=Commands=
 
=Commands=
  
There are various ways to handle your packages:
+
There are various ways to organize your packages:
  
 
* Execute BaseX REPO commands (listed below)
 
* Execute BaseX REPO commands (listed below)
Line 54: Line 49:
 
* Use the GUI (''Options'' → ''Packages'')
 
* Use the GUI (''Options'' → ''Packages'')
  
You can even manually add and remove packages in the repository directory; all changes will automatically be detected by the query processor.
+
You can even manually add and remove packages in the repository directory; all changes will automatically be detected by BaseX.
  
 
==Installation==
 
==Installation==
Line 67: Line 62:
 
==Listing==
 
==Listing==
  
All currently installed packages can be listed with {{Command|REPO LIST}}. It will return the names of all packages, their version, and the directory in which they are installed:
+
All currently installed packages can be listed with {{Command|REPO LIST}}. The names of all packages are listed, along with their version, their package type, and the repository path:
  
  URI                    Version  Directory
+
  Name                  Version  Type      Path
  -------------------------------------------------------
+
  -----------------------------------------------------------------
  <nowiki>http://www.functx.com</nowiki>  1.0      http-www.functx.com-1.0
+
  <nowiki>http://www.functx.com</nowiki>  1.0      EXPath    http-www.functx.com-1.0
 
1 package(s).
 
  
 
==Removal==
 
==Removal==
Line 79: Line 72:
 
A package can be deleted with {{Command|REPO DELETE}} and an additional argument, containing its name or the name suffixed with a hyphen and the package version:
 
A package can be deleted with {{Command|REPO DELETE}} and an additional argument, containing its name or the name suffixed with a hyphen and the package version:
  
  REPO DELETE <nowiki>http://www.functx.com</nowiki> ...or...
+
  REPO DELETE <nowiki>http://www.functx.com</nowiki>
 
  REPO DELETE <nowiki>http://www.functx.com-1.0</nowiki>
 
  REPO DELETE <nowiki>http://www.functx.com-1.0</nowiki>
  
Line 86: Line 79:
 
==XQuery==
 
==XQuery==
  
If an XQuery file is specified as input for the install command, it will be parsed as XQuery library module. If parsing was successful, the module URI will be [[#URI Rewriting|rewritten]] to a file path and attached with the {{Code|.xqm}} file suffix, and the original file will be renamed and copied to that path into the repository.
+
If an XQuery file is specified as input for the install command, it will be parsed as XQuery library module. If the file can successfully be parsed, the module URI will be [[Java Bindings#URI Rewriting|rewritten]] to a file path and attached with the {{Code|.xqm}} file suffix, and the original file will possibly be renamed and copied to that path into the repository.
  
 
'''Example:'''
 
'''Example:'''
Line 96: Line 89:
 
Importing the repository module:
 
Importing the repository module:
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
 
import module namespace m = 'http://basex.org/modules/Hello';
 
import module namespace m = 'http://basex.org/modules/Hello';
 
m:hello("Universe")
 
m:hello("Universe")
</pre>
+
</syntaxhighlight>
  
 
==Java==
 
==Java==
  
For general notes in importing Java classes, please read the Java Bindings article on [[Java Bindings#Module_Imports|Module Imports]].
+
For general notes on importing Java classes, please read the Java Bindings article on [[Java Bindings#Module_Imports|Module Imports]].
  
 
Java archives (JARs) may contain one or more class files. One of them will be chosen as main class, which must be specified in a {{Code|Main-Class}} entry in the manifest file ({{Code|META-INF/MANIFEST.MF}}). This fully qualified Java class name will be rewritten to a file path by replacing the dots with slashes and attaching the {{Code|.jar}} file suffix, and the original file will be renamed and copied to that path into the repository.
 
Java archives (JARs) may contain one or more class files. One of them will be chosen as main class, which must be specified in a {{Code|Main-Class}} entry in the manifest file ({{Code|META-INF/MANIFEST.MF}}). This fully qualified Java class name will be rewritten to a file path by replacing the dots with slashes and attaching the {{Code|.jar}} file suffix, and the original file will be renamed and copied to that path into the repository.
  
If the class will be imported, an instance of it will be created, and its public functions can then be addressed from XQuery. A class may extend the {{Code|QueryModule}} class to get access to the current query context and to be enriched by some helpful annotations (see [[Java_Bindings#Context-Awareness|Context-Awareness]]).
+
If the class will be imported in the prolog of the XQuery module, an instance of it will be created, and its public functions can then be addressed from XQuery. A class may extend the {{Code|QueryModule}} class to get access to the current query context and to be enriched by some helpful annotations (see [[Java_Bindings#Annotations|Annotations]]).
  
 
'''Example:'''
 
'''Example:'''
Line 125: Line 118:
 
Contents of the file {{Code|Hello.java}} (comments removed):
 
Contents of the file {{Code|Hello.java}} (comments removed):
  
<pre class="brush:java">
+
<syntaxhighlight lang="java">
 
package org.basex.modules;
 
package org.basex.modules;
 
public class Hello {
 
public class Hello {
Line 132: Line 125:
 
   }
 
   }
 
}
 
}
</pre>
+
</syntaxhighlight>
  
 
Installation (the file will be copied to {{Code|org/basex/modules/Hello.jar}}):
 
Installation (the file will be copied to {{Code|org/basex/modules/Hello.jar}}):
Line 140: Line 133:
 
XQuery file <code>[http://files.basex.org/modules/org/basex/modules/Hello/HelloUniverse.xq HelloUniverse.xq]</code> (same as above):
 
XQuery file <code>[http://files.basex.org/modules/org/basex/modules/Hello/HelloUniverse.xq HelloUniverse.xq]</code> (same as above):
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
 
import module namespace m = 'http://basex.org/modules/Hello';
 
import module namespace m = 'http://basex.org/modules/Hello';
 
m:hello("Universe")
 
m:hello("Universe")
</pre>
+
</syntaxhighlight>
  
After having installed the module, all of the following URIs can be used in XQuery to import this module or call its functions (see [[#URI Rewriting|URI Rewriting]] for more information):
+
After having installed the module, all of the following URIs can be used in XQuery to import this module or call its functions (see [[Java Bindings#URI Rewriting|URI Rewriting]] for more information):
  
 
  <nowiki>http://basex.org/modules/Hello</nowiki>
 
  <nowiki>http://basex.org/modules/Hello</nowiki>
 
  org/basex/modules/Hello
 
  org/basex/modules/Hello
 
  org.basex.modules.Hello
 
  org.basex.modules.Hello
 +
 +
===Additional Libraries===
 +
 +
A Java class may depend on additional libraries. The dependencies can be resolved by creating a fat JAR file, i.e., extracting all files of the library archives and producing a single, flat JAR package.
 +
 +
Another solution is to copy the libraries into a {{Code|lib}} directory of the JAR package. If the package will be installed, the additional library archives will be extracted and copied to a hidden sub-directory in the repository. If the package will be deleted, the hidden sub-directory will be removed as well.
 +
 +
; Examplary contents of {{Code|Image.jar}}
 +
 +
lib/
 +
  Images.jar
 +
META-INF/
 +
  MANIFEST.MF
 +
org/basex/modules/
 +
  Image.class
 +
 +
; Directory structure of the repository directory after installing the package
 +
 +
org/basex/modules/
 +
  Image.class
 +
  .Images/
 +
    Images.jar
 +
 +
==Combined==
 +
 +
It makes sense to combine the advantages of XQuery and Java packages:
 +
 +
* Instead of directly calling Java code, a wrapper module can be provided. This module contains functions that invoke the Java functions.
 +
* These functions can be strictly typed. This reduces the danger of erroneous or unexpected conversions between XQuery and Java code.
 +
* In addition, the entry functions can have properly maintained XQuery comments.
 +
 +
XQuery and Java can be combined as follows:
 +
 +
* First, a JAR package is created (as described above).
 +
* A new XQuery wrapper module is created, which is named identically to the Java main class.
 +
* The URL of the {{Code|import module}} statement in the wrapper module must start with the {{Code|java:}} prefix.
 +
* The finalized XQuery module must be copied into the JAR file, and placed in the same directory as the Java main class.
 +
 +
If the resulting JAR file is installed, the embedded XQuery module will be extracted, and will be called first if the module will be imported.
 +
 +
; Main Module {{Code|hello-universe.xq}}:
 +
 +
<syntaxhighlight lang="xquery">
 +
import module namespace m = 'http://basex.org/modules/Hello';
 +
m:hello("Universe")
 +
</syntaxhighlight>
 +
 +
; Wrapper Module {{Code|Hello.xqm}}:
 +
 +
<syntaxhighlight lang="xquery">
 +
module namespace hello = 'http://basex.org/modules/Hello';
 +
 +
(: Import JAR file :)
 +
import module namespace java = 'java:org.basex.modules.Hello';
 +
 +
(:~
 +
: Say hello to someone.
 +
: @param  $world  the one to be greeted
 +
: @return welcome string
 +
:)
 +
declare function hello:hello(
 +
  $world  as xs:string
 +
) as xs:string {
 +
  java:hello($world)
 +
};
 +
</syntaxhighlight>
 +
 +
; Java class {{Code|Hello.java}}:
 +
 +
<syntaxhighlight lang="java">
 +
package org.basex.modules;
 +
 +
public class Hello {
 +
  public String hello(final String world) {
 +
    return "Hello " + world;
 +
  }
 +
}
 +
</syntaxhighlight>
 +
 +
If the JAR file is installed, {{Code|Combined}} will be displayed as type:
 +
 +
REPO INSTALL http://files.basex.org/modules/org/basex/modules/Hello.jar
 +
REPO LIST
 +
 +
Name                    Version  Type      Path
 +
-----------------------------------------------------------------------
 +
org.basex.modules.Hello  -        Combined  org/basex/modules/Hello.xqm
  
 
=EXPath Packaging=
 
=EXPath Packaging=
Line 159: Line 239:
 
Apart from the package descriptor, a {{Code|.xar}} archive contains a directory which includes the actual XQuery modules. For example, the [http://files.basex.org/modules/expath/functx-1.0.xar FunctX XAR archive] is packaged as follows:
 
Apart from the package descriptor, a {{Code|.xar}} archive contains a directory which includes the actual XQuery modules. For example, the [http://files.basex.org/modules/expath/functx-1.0.xar FunctX XAR archive] is packaged as follows:
  
<pre>
+
<syntaxhighlight>
 
expath-pkg.xml
 
expath-pkg.xml
 
functx/
 
functx/
 
   functx.xql
 
   functx.xql
 
   functx.xsl
 
   functx.xsl
</pre>
+
</syntaxhighlight>
  
 
==Java==
 
==Java==
  
In case you want to extend BaseX with a Java archive, some additional requirements have to be fulfilled:
+
If you want to package an EXPath archive with Java code, some additional requirements have to be fulfilled:
  
 
* Apart from the package descriptor <code>expath-pkg.xml</code>, the package has to contain a descriptor file at its root, defining the included jars and the binary names of their public classes. It must be named <code>basex.xml</code> and must conform to the following structure:
 
* Apart from the package descriptor <code>expath-pkg.xml</code>, the package has to contain a descriptor file at its root, defining the included jars and the binary names of their public classes. It must be named <code>basex.xml</code> and must conform to the following structure:
  
<pre class="brush:xml">
+
<syntaxhighlight lang="xml">
 
<package xmlns="http://expath.org/ns/pkg">
 
<package xmlns="http://expath.org/ns/pkg">
 
   <jar>...</jar>
 
   <jar>...</jar>
Line 180: Line 260:
 
     ....
 
     ....
 
</package>
 
</package>
</pre>
+
</syntaxhighlight>
  
 
* The jar file itself along with an XQuery file defining wrapper functions around the java methods has to reside in the module directory. The following example illustrates how java methods are wrapped with XQuery functions:
 
* The jar file itself along with an XQuery file defining wrapper functions around the java methods has to reside in the module directory. The following example illustrates how java methods are wrapped with XQuery functions:
Line 186: Line 266:
 
'''Example:'''<br>Suppose we have a simple class <code>Printer</code> having just one public method <code>print()</code>:
 
'''Example:'''<br>Suppose we have a simple class <code>Printer</code> having just one public method <code>print()</code>:
  
<pre class="brush:java">
+
<syntaxhighlight lang="java">
 
package test;
 
package test;
  
Line 194: Line 274:
 
   }
 
   }
 
}
 
}
</pre>
+
</syntaxhighlight>
  
 
We want to extend BaseX with this class and use its method. In order to make this possible we have to define an XQuery function which wraps the <code>print</code> method of our class. This can be done in the following way:
 
We want to extend BaseX with this class and use its method. In order to make this possible we have to define an XQuery function which wraps the <code>print</code> method of our class. This can be done in the following way:
  
<pre class="brush:xquery">
+
<syntaxhighlight lang="xquery">
 
import module namespace j="http://basex.org/lib/testJar";
 
import module namespace j="http://basex.org/lib/testJar";
  
Line 207: Line 287:
 
   return p:print($printer, $str)
 
   return p:print($printer, $str)
 
};
 
};
</pre>
+
</syntaxhighlight>
  
 
As it can be seen, the class {{Code|Printer}} is declared with its binary name as a namespace prefixed with "java" and the XQuery function is implemented using the [http://docs.basex.org/wiki/Java_Bindings Java Bindings] offered by BaseX.
 
As it can be seen, the class {{Code|Printer}} is declared with its binary name as a namespace prefixed with "java" and the XQuery function is implemented using the [http://docs.basex.org/wiki/Java_Bindings Java Bindings] offered by BaseX.
Line 213: Line 293:
 
On our [http://files.basex.org/modules/ file server], you can find some example libraries packaged as XML archives (xar files). You can use them to try our packaging API or just as a reference for creating your own packages.
 
On our [http://files.basex.org/modules/ file server], you can find some example libraries packaged as XML archives (xar files). You can use them to try our packaging API or just as a reference for creating your own packages.
  
=URI Rewriting=
+
=Performance=
 
 
If a module is looked up in the repository, the namespace URI is rewritten to a local file path:
 
 
 
# If the URI is a URL:
 
## colons will be replaced with slashes,
 
## in the URI authority, the order of all substrings separated by dots is reversed, and
 
## dots in the authority and the path are replaced by slashes. If no path exists, a single slash is appended.
 
# Otherwise, if the URI is a URN, colons will be replaced with slashes.
 
# Characters other than letters, dots and slashes will be replaced with dashes.
 
# If the resulting string ends with a slash, the {{Code|index}} string is appended.
 
  
If the resulting path has no file suffix, it may point to either an XQuery module or a Java archive.
+
Importing XQuery modules that are located in the repository is just as fast as importing any other modules. Modules that are imported several times in a project will only be compiled once.
The following examples show some rewritings:
 
  
* {{Code|<nowiki>http://basex.org/modules/hello/World</nowiki>}} → {{Code|org/basex/modules/hello/World}}
+
Imported Java archives will be dynamically added to the classpath and unregistered after query execution. This requires some constant overhead and may lead to unexpected effects in scenarios with highly concurrent read operations. If you want to get optimal performance, it is recommendable to move your JAR files into the {{Code|lib/custom}} directory of BaseX. This way, the archive will be added to the classpath if BaseX is started. If you have installed a [[#Combined|Combined Package]], you can simply keep your XQuery module in the repository, and the Java classes will be automatically detected.
* {{Code|<nowiki>http://www.example.com</nowiki>}} → {{Code|com/example/www/index}}
 
* {{Code|a/little/example}} → {{Code|a/little/example}}
 
* {{Code|a:b:c}} → {{Code|a/b/c}}
 
  
 
=Changelog=
 
=Changelog=
  
;Version 8.2
+
;Version 9.0
  
* Added: [[#URI Rewriting|URI Rewriting]]: support for URNs
+
* Added: [[#Combined|Combined]] XQuery and Java packages
 +
* Added: [[#Additional Libraries|Additional Libraries]]
  
 
;Version 7.2.1
 
;Version 7.2.1
Line 243: Line 310:
 
* Updated: [[#Installation|Installation]]: existing packages will be replaced without raising an error
 
* Updated: [[#Installation|Installation]]: existing packages will be replaced without raising an error
 
* Updated: [[#Removal|Removal]]: remove specific version of a package
 
* Updated: [[#Removal|Removal]]: remove specific version of a package
* Added: [[#Packaging|Packaging]], [[#URI Rewriting|URI Rewriting]]
 
  
 
;Version 7.1
 
;Version 7.1

Revision as of 13:14, 27 February 2020

This article is part of the XQuery Portal. It describes how external XQuery modules and Java code can be installed in the XQuery module repository, and how new packages are built and deployed.

Introduction

One of the things that makes languages successful is the availability of external libraries. As XQuery comes with only 150 pre-defined functions, which cannot meet all requirements, additional library modules exist – such as FunctX – which extend the language with new features.

BaseX offers the following mechanisms to make external modules accessible to the XQuery processor:

  1. The internal Packaging mechanism will install single XQuery and JAR modules in the repository.
  2. The EXPath Packaging system provides a generic mechanism for adding XQuery modules to query processors. A package is defined as a .xar archive, which encapsulates one or more extension libraries.

Accessing Modules

Library modules can be imported with the import module statement, followed by a freely choosable prefix and the namespace of the target module. The specified location may be absolute or relative; in the latter case, it is resolved against the location (i.e., static base URI) of the calling module. Import module statements must be placed at the beginning of a module:

Main Module hello-universe.xq:

<syntaxhighlight lang="xquery"> import module namespace m = 'http://basex.org/modules/hello' at 'hello-world.xqm'; m:hello("Universe") </syntaxhighlight>

Library Module hello-world.xqm (in the same directory):

<syntaxhighlight lang="xquery"> module namespace m = 'http://basex.org/modules/Hello'; declare function m:hello($world) {

 'Hello ' || $world

}; </syntaxhighlight>

If no location is supplied, modules will be looked up in the repository. Repository modules are stored in the repo directory, which resides in your home directory. XQuery modules can be manually copied to the repository directory or installed and deleted via commands.

The following example calls a function from the FunctX module in the repository:

<syntaxhighlight lang="xquery"> import module namespace functx = 'http://www.functx.com'; functx:capitalize-first('test') </syntaxhighlight>

Commands

There are various ways to organize your packages:

  • Execute BaseX REPO commands (listed below)
  • Call XQuery functions of the Repository Module
  • Use the GUI (OptionsPackages)

You can even manually add and remove packages in the repository directory; all changes will automatically be detected by BaseX.

Installation

A module or package can be installed with REPO INSTALL. The path to the file has to be given as a parameter:

REPO INSTALL http://files.basex.org/modules/expath/functx-1.0.xar
REPO INSTALL hello-world.xqm

The installation will only succeed if the specified file conforms to the constraints described below. If you know that your input is valid, you may as well copy the files directly to the repository directory, or edit its contents in the repository without deleting and reinstalling them.

Listing

All currently installed packages can be listed with REPO LIST. The names of all packages are listed, along with their version, their package type, and the repository path:

Name                   Version  Type      Path
-----------------------------------------------------------------
http://www.functx.com  1.0      EXPath    http-www.functx.com-1.0

Removal

A package can be deleted with REPO DELETE and an additional argument, containing its name or the name suffixed with a hyphen and the package version:

REPO DELETE http://www.functx.com
REPO DELETE http://www.functx.com-1.0

Packaging

XQuery

If an XQuery file is specified as input for the install command, it will be parsed as XQuery library module. If the file can successfully be parsed, the module URI will be rewritten to a file path and attached with the .xqm file suffix, and the original file will possibly be renamed and copied to that path into the repository.

Example:

Installation (the original file will be copied to the org/basex/modules/Hello sub-directory of the repository):

REPO INSTALL http://files.basex.org/modules/org/basex/modules/Hello/HelloWorld.xqm

Importing the repository module:

<syntaxhighlight lang="xquery"> import module namespace m = 'http://basex.org/modules/Hello'; m:hello("Universe") </syntaxhighlight>

Java

For general notes on importing Java classes, please read the Java Bindings article on Module Imports.

Java archives (JARs) may contain one or more class files. One of them will be chosen as main class, which must be specified in a Main-Class entry in the manifest file (META-INF/MANIFEST.MF). This fully qualified Java class name will be rewritten to a file path by replacing the dots with slashes and attaching the .jar file suffix, and the original file will be renamed and copied to that path into the repository.

If the class will be imported in the prolog of the XQuery module, an instance of it will be created, and its public functions can then be addressed from XQuery. A class may extend the QueryModule class to get access to the current query context and to be enriched by some helpful annotations (see Annotations).

Example:

Structure of the HelloWorld.jar archive:

META-INF/
  MANIFEST.MF
org/basex/modules/
  Hello.class

Contents of the file MANIFEST.mf (the whitespaces are obligatory):

Manifest-Version: 1.0
Main-Class: org.basex.modules.Hello

Contents of the file Hello.java (comments removed):

<syntaxhighlight lang="java"> package org.basex.modules; public class Hello {

 public String hello(final String world) {
   return "Hello " + world;
 }

} </syntaxhighlight>

Installation (the file will be copied to org/basex/modules/Hello.jar):

REPO INSTALL HelloWorld.jar

XQuery file HelloUniverse.xq (same as above):

<syntaxhighlight lang="xquery"> import module namespace m = 'http://basex.org/modules/Hello'; m:hello("Universe") </syntaxhighlight>

After having installed the module, all of the following URIs can be used in XQuery to import this module or call its functions (see URI Rewriting for more information):

http://basex.org/modules/Hello
org/basex/modules/Hello
org.basex.modules.Hello

Additional Libraries

A Java class may depend on additional libraries. The dependencies can be resolved by creating a fat JAR file, i.e., extracting all files of the library archives and producing a single, flat JAR package.

Another solution is to copy the libraries into a lib directory of the JAR package. If the package will be installed, the additional library archives will be extracted and copied to a hidden sub-directory in the repository. If the package will be deleted, the hidden sub-directory will be removed as well.

Examplary contents of Image.jar
lib/
  Images.jar
META-INF/
  MANIFEST.MF
org/basex/modules/
  Image.class
Directory structure of the repository directory after installing the package
org/basex/modules/
  Image.class
  .Images/
    Images.jar

Combined

It makes sense to combine the advantages of XQuery and Java packages:

  • Instead of directly calling Java code, a wrapper module can be provided. This module contains functions that invoke the Java functions.
  • These functions can be strictly typed. This reduces the danger of erroneous or unexpected conversions between XQuery and Java code.
  • In addition, the entry functions can have properly maintained XQuery comments.

XQuery and Java can be combined as follows:

  • First, a JAR package is created (as described above).
  • A new XQuery wrapper module is created, which is named identically to the Java main class.
  • The URL of the import module statement in the wrapper module must start with the java: prefix.
  • The finalized XQuery module must be copied into the JAR file, and placed in the same directory as the Java main class.

If the resulting JAR file is installed, the embedded XQuery module will be extracted, and will be called first if the module will be imported.

Main Module hello-universe.xq

<syntaxhighlight lang="xquery"> import module namespace m = 'http://basex.org/modules/Hello'; m:hello("Universe") </syntaxhighlight>

Wrapper Module Hello.xqm

<syntaxhighlight lang="xquery"> module namespace hello = 'http://basex.org/modules/Hello';

(: Import JAR file :) import module namespace java = 'java:org.basex.modules.Hello';

(:~

: Say hello to someone.
: @param  $world  the one to be greeted
: @return welcome string
:)

declare function hello:hello(

 $world  as xs:string

) as xs:string {

 java:hello($world)

}; </syntaxhighlight>

Java class Hello.java

<syntaxhighlight lang="java"> package org.basex.modules;

public class Hello {

 public String hello(final String world) {
   return "Hello " + world;
 }

} </syntaxhighlight>

If the JAR file is installed, Combined will be displayed as type:

REPO INSTALL http://files.basex.org/modules/org/basex/modules/Hello.jar
REPO LIST

Name                     Version  Type      Path
-----------------------------------------------------------------------
org.basex.modules.Hello  -        Combined  org/basex/modules/Hello.xqm

EXPath Packaging

The EXPath specification defines how the structure of a .xar archive shall look like. The package contains at its root a package descriptor named expath-pkg.xml. This descriptor presents some meta data about the package as well as the libraries which it contains and their dependencies on other libraries or processors.

XQuery

Apart from the package descriptor, a .xar archive contains a directory which includes the actual XQuery modules. For example, the FunctX XAR archive is packaged as follows:

<syntaxhighlight> expath-pkg.xml functx/

 functx.xql
 functx.xsl

</syntaxhighlight>

Java

If you want to package an EXPath archive with Java code, some additional requirements have to be fulfilled:

  • Apart from the package descriptor expath-pkg.xml, the package has to contain a descriptor file at its root, defining the included jars and the binary names of their public classes. It must be named basex.xml and must conform to the following structure:

<syntaxhighlight lang="xml"> <package xmlns="http://expath.org/ns/pkg">

 <jar>...</jar>
   ....
   <class>...</class>
   <class>...</class>
   ....

</package> </syntaxhighlight>

  • The jar file itself along with an XQuery file defining wrapper functions around the java methods has to reside in the module directory. The following example illustrates how java methods are wrapped with XQuery functions:

Example:
Suppose we have a simple class Printer having just one public method print():

<syntaxhighlight lang="java"> package test;

public final class Printer {

 public String print(final String s) {
   return new Writer(s).write();
 }

} </syntaxhighlight>

We want to extend BaseX with this class and use its method. In order to make this possible we have to define an XQuery function which wraps the print method of our class. This can be done in the following way:

<syntaxhighlight lang="xquery"> import module namespace j="http://basex.org/lib/testJar";

declare namespace p="java:test.Printer";

declare function j:print($str as xs:string) as xs:string {

 let $printer := p:new()
 return p:print($printer, $str)

}; </syntaxhighlight>

As it can be seen, the class Printer is declared with its binary name as a namespace prefixed with "java" and the XQuery function is implemented using the Java Bindings offered by BaseX.

On our file server, you can find some example libraries packaged as XML archives (xar files). You can use them to try our packaging API or just as a reference for creating your own packages.

Performance

Importing XQuery modules that are located in the repository is just as fast as importing any other modules. Modules that are imported several times in a project will only be compiled once.

Imported Java archives will be dynamically added to the classpath and unregistered after query execution. This requires some constant overhead and may lead to unexpected effects in scenarios with highly concurrent read operations. If you want to get optimal performance, it is recommendable to move your JAR files into the lib/custom directory of BaseX. This way, the archive will be added to the classpath if BaseX is started. If you have installed a Combined Package, you can simply keep your XQuery module in the repository, and the Java classes will be automatically detected.

Changelog

Version 9.0
Version 7.2.1
  • Updated: Installation: existing packages will be replaced without raising an error
  • Updated: Removal: remove specific version of a package
Version 7.1
Version 7.0