Powerful Collection Management
Apache Xindice is quite simply an implementation of a native XML database using Java. Xindice provides an implementation of XPath for its query language and XUpdate for its update language. Additionally, Xindice implements the XML:DB API. The XML:DB API is conceptually similar to ODBC and JDBC, but it has different levels of interoperability. The Xindice implementation is core level 1 with some optional services such as XUpdate and CollectionManagement, and it can be accessed using CORBA, Java, or XML:RPC.
Further, Xindice provides some proprietary functionality as well as experimental features, which are beyond the scope of this article. Instead I will cover how to insert, select, update, and delete XML data using the Java API and how to manage collections using the proprietary CollectionManager service. Xindice's proprietary CollectionManager service is much more powerful than the XML:DB CollectionManagement service. For example, Xindice's proprietary CollectionManager service allows for collection configurations that are specific to Xindice such as GZip compression and indexes.
Xindice stores all XML documents inside of collections. Thus every XML document must be stored in at least one collection. Collections can be nested and are considered part of an XPath query string, so there is always a root collection. While collections can be used strictly for organizational purposes, Xindice also allows for indexes to be created on collections to increase XPath performance. I am not going to use indexes in this article as all my examples will work on generic XML data; creating indexes would require contextual understanding of the XML data.
I plan to create a single wrapper class to hold all of my examples for working with Xindice. To get started I need to do various imports, set up the shell class, and declare some class properties for later use.
public class DBManager
Collection col = null;
Class c = null;
Database database = null;
public DBManager() throws Exception
c = Class.forName("org.apache.xindice.client.xmldb.
database = (Database) c.newInstance();
The above code imports all of the needed classes for the XML:DB API as well as some specific to Xindice. Because org.xmldb.api.base.Database is a generic interface for working with XML databases, I need to create an instance of the Xindice driver that implements the Database interface. Instead of working with the Xindice implementation specifically, I cast it to down to the interface to ensure my code is interoperable. Finally, I register the database driver.
With my shell class created I am ready to move on to creating my first collection. Much like documents, collections must be created inside of other collections. When Xindice was started it used its configured database instance as the root collection, which by default is named db. Thus I am going to create my new collection in the db collection. I will do this with a method named createCollection that accepts a single String as a parameter indicating the collection name. The method body follows:
col = DatabaseManager.getCollection("xmldb:xindice:///db/");
CollectionManager service =
(CollectionManager) col.getService("CollectionManager", "1.0");
String collectionConfig =
"<collection compressed=\"true\" name=\"" + collection + "\">" +
filer.BTreeFiler\" gzip=\"true\"/>" +
Again, the first thing I need in order to create a collection is another collection to create it in. I use the getCollection method to obtain a reference to the root collection named db. After that I need a CollectionManagement service, so I ask for the proprietary CollectionManager offered by Xindice. While it would be possible to use the generic CollectionManagement service to create a simple collection, Xindice offers more powerful features that are only available using its proprietary service. The createCollection method takes a collection name and XML configuration string as parameters. My configuration string is pretty simply: the only unusual feature is that I ask for compression using GZip
. Take a look at the Xindice documentation
for all the possible collection configuration options.
To insert data I am going to create a method that accepts two string parameters: ID and data. All documents in a collection must be uniquely identified, much like rows in a database. I am using the ID passed to the method as the unique identifier. However, if you pass a null or empty string as the value of ID to the createResource method Xindice will generate a unique identifier for you using the createId method. My preference is to call the createId method myself, so I can more easily identify the document. For simplicity, my method will just assume the ID passed is valid. Below is the body of the method.
XMLResource document = (XMLResource)
As you can see, inserting data into Xindice is quite easy. It should be noted that createResource can handle more than just XML data. With Xindice, createResource can also create a BinaryResource. Other XML databases will vary in their support for other types of resources, so if you aren't using Xindice then it's imperative to check the documentation for the database you are using.