XQJ Tutorial Part II: Setting up an XQJ Session



XQJ is designed to accommodate the differences that can exist across XQuery implementations in terms of architecture and the range of supported data sources. For example, depending on the XQJ and XQuery implementation, the parameters and settings needed to configure the implementation might be different. Some implementations are server based and require information to locate the server, for example. Or, if the XQJ and XQuery implementations are co-located, you might need to specify the default location to query files on the local file system. Let's take a closer look at how connections work in XQJ.

The XQDataSource Object

An XQJ application always starts with accessing an XQDataSource object. Such an object encapsulates all the parameters and settings needed to create a session with a specific implementation, and eventually execute XQuery expressions and process the results.

Every XQJ driver has its own XQDataSource implementation. This XQDataSource object supports a number of implementation-specific properties. For each of these properties, "getter" and "setter" methods are provided.

Assume an application wants to query both an Oracle database and some files located in "/usr/joe/data" using the DataDirect XQuery® engine. Two properties need to be specified:

  • The base URI, which is used to retrieve the files in our folder without explicitly referencing the folder in the XQuery
  • , and
  • The JDBC URL, which is used to connect to the Oracle database (feel free to replace Oracle with your favorite database, be it SQL Server, MySQL or any other)

Here's what the DataDirect XQuery implementation of the XQDataSource object, DDXQDataSource, needed to specify these settings would look like:

DDXQDataSource xqds = new DDXQDataSource();
xqds.setBaseUri("/usr/joe/data");
xqds.setJdbcUrl("jdbc:xquery:oracle://sales:1521;SID=ORA10");

Now think about a different XQuery implementation, perhaps one provided by Oracle, in which the server parameters are specified as individual properties rather than through a JDBC URL. It could be expressed as something like this:

OracleDataSource xqds = new OracleDataSource();
xqds.setServerName("sales");
xqds.setPortNumber(1521);
xqds.setSID("ORA10");

Establishing a Session

Once we have access to an XQDataSource object, what's next? An XQDataSource is a factory for XQConnection objects. The XQConnection object represents a session in which XQuery expressions are executed. Establishing such a session is straightforward:

XQConnection xqc = xqds.getConnection();

If required, user credentials can be specified as arguments to the getConnection() method:

XQConnection xqc = xqds.getConnection("joe", "topsecret");

Making Applications Independent

You might have noticed that using the approach outlined so far to create XQDataSource objects makes the application dependent on a specific XQJ implementation — the proprietary classes DDXQDataSource (DataDirect XQuery®) and OracleDataSource, for example.

This is not necessarily wrong — there are scenarios in which hard-coding the underlying XQJ implementation makes sense — but it's not always desirable. After all, one of the benefits of XQJ is the ability to make your applications independent from the underlying XQuery implementation. How can we achieve that? We'll show two approaches:

  • Using a Java properties files
  • Through the Java Naming and Directory Interface (JNDI)

Using Properties Files

Assume all the XQDataSource properties are stored in a Java properties file, and in addition a property ClassName is specified to identify the XQDataSource implementation that needs to be used.

For the DataDirect XQuery® example above, the properties file would look like this:

ClassName = com.ddtek.xquery3.xqj.DDXQDataSource
BaseUri = /usr/joe/data
JdbcUrl = jdbc:xquery:oracle://sales:1521;SID=ORA10

For the Oracle implementation:

ClassName = org.example.xqj.OracleDataSource
ServerName = sales
PortNumber = 1521
SID = ORA10

Using such property files, an application can easily abstract out any hard-coded dependencies on the underlying XQJ implementation. The XQDataSource class is loaded through reflection and the next step is to simply provide the property file:

// load the property file
Properties p = new Properties();
p.load(new FileInputStream("/tmp/xqjds.prop"));

// create an XQDataSource instance using reflection
String xqdsClassName = properties.getProperty("ClassName");
Class xqdsClass = Class.forName(xqdsClassName);
XQDataSource xqds = (XQDataSource)xqdsClass.newInstance();

// remove the ClassName property
// the XQJ implementation will not recognize it and raise an error
p.remove("ClassName");

// set the remaining properties
xqds.setProperties(tmpProperties);

// create an XQConnection
XQConnection xqc = xqds.getConnection();

Of course, this is just an example; it might well be that for some applications different ways to load the datasource properties are better suited.

Using JNDI

Similarly to JDBC, the XQDataSource object can be stored in a JNDI-enabled naming service when running in a Java EE environment. This allows applications to access the XQDataSource by simply specifying a logical name:

// get the initial JNDI context
Context ctx = new InitialContext();
// load the XQDataSource instance
XQDataSource xqds = (XQDataSource)ctx.lookup("xqj/sales");
// create an XQConnection
XQConnection xqc = xqds.getConnection();

If you have a JDBC background, you are probably familiar with the fact that JDBC has two mechanisms to establish a connection:

  • DriverManager
  • DataSource

Don't look in XQJ for DriverManager-like functionality; XQJ doesn't offer this legacy functionality.

At this point you know how to create an XQConnection. Now you're ready to do some "real work" and execute queries.