/**
* XMLNodeAsXQueryParameterTest.java
*
* 2005 by O2 IT Engineering
* Zurich, Switzerland (CH)
*/
package org.exist.xquery;
import org.exist.storage.DBBroker;
import org.exist.xmldb.XQueryService;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.CompiledExpression;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.ResourceSet;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import junit.framework.TestCase;
/**
* Class to test eXist's capability to handle XML Nodes as XQuery parameter.
*
* @author Tobias Wunden
* @version 1.0
*/
public class XMLNodeAsXQueryParameterTest extends TestCase {
/** eXist database url */
static final String eXistUrl ="xmldb:exist://";
public static void main(String[] args) {
junit.textui.TestRunner.run(XMLNodeAsXQueryParameterTest.class);
}
/**
* This test passes a W3C dom node as an xquery parameter to eXist and tries
* to read it back in:
* <ul>
* <li>Register a database instance</li>
* <li>Write a document to the database using the XQueryService</li>
* <li>Read the document from the database using XmlDB</li>
* <li>Check for the document content</li>
* </ul>
*/
public final void testXMLNodeAsXQueryParameter() {
Database eXist = null;
String document = "test.xml";
try {
eXist = registerDatabase();
} catch (XMLDBException e) {
fail("Unable to register database: " + e.getMessage());
}
// Obtain XQuery service
XQueryService service = null;
try {
service = getXQueryService(eXist);
if (service == null) {
fail("Failed to obtain xquery service instance!");
}
} catch (Exception e) {
fail("Failed to obtain xquery service instance: " + e.getMessage());
}
// create document
StringBuffer xmlDocument = new StringBuffer();
xmlDocument.append("<XmlNodeTest/>");
// write document to the database
try {
store(xmlDocument.toString(), service, document);
} catch (Exception e) {
fail("Failed to write document to database: " + e.getMessage());
}
// add content using XUpdate
StringBuffer xmlData = new StringBuffer();
xmlData.append("<content/>");
try {
InputSource is = new InputSource(new StringReader(xmlData.toString()));
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = docBuilder.parse(is);
xupdate(service, doc.getFirstChild());
} catch (SAXException e) {
fail("Error building dom tree: " + e.getMessage());
} catch (IOException e) {
fail("Error reading xml: " + e.getMessage());
} catch (ParserConfigurationException e) {
fail("Error parsing xml: " + e.getMessage());
} catch (FactoryConfigurationError e) {
fail("Error receiving dom factory: " + e.getMessage());
} catch (Exception e) {
fail("Failed to update document in database: " + e.getMessage());
}
// read document back from database
Node root = null;
try {
root = load(service, document);
if (root == null) {
fail("Document " + document + " was not found in the database!");
}
} catch (Exception e) {
fail("Failed to write document to database: " + e.getMessage());
}
// issue xpath query
try {
Node node = root.getFirstChild();
if (node != null) {
System.out.println("Found '" + node.getNodeName() + "'");
} else {
fail("XUpdate:append using w3c dom node failed! Content node was not returned.");
}
} catch (Exception e) {
fail("Failed to issue xpath on root node: " + e.getMessage());
}
}
/**
* Stores the given xml fragment into the database.
*
* @param xml the xml document
* @param service the xquery service
* @param document the document name
* @throws XMLDBException on database error
*/
private final void store(String xml, XQueryService service, String document) throws XMLDBException {
StringBuffer query = new StringBuffer();
query.append("xquery version \"1.0\";");
query.append("declare namespace xdb=\"http://exist-db.org/xquery/xmldb\";");
query.append("let $loggedIn := xdb:login(\"" + DBBroker.ROOT_COLLECTION + "\", \"admin\", \"admin\"),");
query.append("$doc := xdb:store(\"" + DBBroker.ROOT_COLLECTION + "\", $document, $data)");
query.append("return <result/>");
service.declareVariable("document", document);
service.declareVariable("data", xml);
CompiledExpression cQuery = service.compile(query.toString());
service.execute(cQuery);
}
/**
* Updates the given xml fragment in the database using XUpdate.
*
* @param service the xquery service
* @param data the data node
* @throws XMLDBException on database error
*/
private final void xupdate(XQueryService service, Object data) throws XMLDBException {
if (data == null) {
fail("Cannot update because data is 'null'");
}
StringBuffer query = new StringBuffer();
query.append("xquery version \"1.0\";");
query.append("declare namespace xdb=\"http://exist-db.org/xquery/xmldb\";");
query.append("declare variable $xupdate {");
query.append("<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">");
query.append("<xu:append select=\"xmldb:xcollection('" + DBBroker.ROOT_COLLECTION + "')/XmlNodeTest\">");
query.append("{$data}");
query.append("</xu:append>");
query.append("</xu:modifications>");
query.append("};");
query.append("let $isLoggedIn := xdb:login('" + eXistUrl + DBBroker.ROOT_COLLECTION + "', \"admin\", \"admin\"),");
query.append("$mods := xdb:update(\"" + eXistUrl + DBBroker.ROOT_COLLECTION + "\", $xupdate)");
query.append("return <modifications>{$mods}</modifications>");
service.declareVariable("data", data);
CompiledExpression cQuery = service.compile(query.toString());
service.execute(cQuery);
}
/**
* Loads the xml document identified by <code>document</code> from the database.
*
* @param service the xquery service
* @param document the document to load
* @throws XMLDBException on database error
*/
private final Node load(XQueryService service, String document) throws XMLDBException {
StringBuffer query = new StringBuffer();
query.append("xquery version \"1.0\";");
query.append("let $survey := xmldb:document(concat('" + DBBroker.ROOT_COLLECTION + "', '/', $document))");
query.append("return ($survey)");
service.declareVariable("document", document);
CompiledExpression cQuery = service.compile(query.toString());
ResourceSet set = service.execute(cQuery);
if (set != null && set.getSize() > 0) {
return ((XMLResource)set.getIterator().nextResource()).getContentAsDOM();
}
return null;
}
/**
* Registers a new database instance and returns it.
*
* @throws XMLDBException
*/
private final Database registerDatabase() throws XMLDBException {
Class driver = null;
String driverName = "org.exist.xmldb.DatabaseImpl";
try {
driver = Class.forName(driverName);
Database database = (Database)driver.newInstance();
database.setProperty("create-database", "true");
DatabaseManager.registerDatabase(database);
return database;
} catch (ClassNotFoundException e) {
System.err.println("Driver class " + driverName + " was not found!");
throw new XMLDBException();
} catch (InstantiationException e) {
System.err.println("Driver class " + driverName + " could not be instantiated!");
throw new XMLDBException();
} catch (IllegalAccessException e) {
System.err.println("Access violation when trying to instantiate XMLDB Driver " + driverName + "!");
throw new XMLDBException();
}
}
/**
* Retrieves the base collection and thereof returns a reference to the collection's
* xquery service.
*
* @param db the database
* @return the xquery service
* @throws XMLDBException on database error
*/
private final XQueryService getXQueryService(Database db) throws XMLDBException {
Collection collection = DatabaseManager.getCollection(eXistUrl + DBBroker.ROOT_COLLECTION, "admin", "admin");
if (collection != null) {
XQueryService service = (XQueryService)collection.getService("XQueryService", "1.0");
collection.close();
return service;
}
return null;
}
}