package org.exist.xmldb;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Random;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import junit.framework.TestCase;
import org.exist.storage.DBBroker;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xmldb.api.DatabaseManager;
import org.xmldb.api.base.Collection;
import org.xmldb.api.base.Database;
import org.xmldb.api.base.XMLDBException;
import org.xmldb.api.modules.XMLResource;
/** Reproduce the EXistException "the document is too complex/irregularily structured
* to be mapped into eXist's numbering scheme"
* raised in {@link org.exist.dom.DocumentImpl} .
* It creates with DOM a simple document having a branch of 16 elements depth
* connected to the root, with width (arity) of 16 at each level.
*/
public class IndexingTest extends TestCase {
private int siblingCount;
private int depth;
private Node deepBranch;
private Random random;
private static String driver = "org.exist.xmldb.DatabaseImpl";
private static String baseURI = "xmldb:exist://" + DBBroker.ROOT_COLLECTION;
private static String username = "admin";
private static String password = ""; // <<<
private static String name = "test.xml";
private String EXIST_HOME = ""; // <<<
private int effectiveSiblingCount;
private int effectiveDepth;
private long startTime;
private int arity;
private boolean randomSizes;
/**
* @see junit.framework.TestCase#setUp()
*/
protected void setUp() {
siblingCount = 2;
depth = 16;
arity = 16;
randomSizes = false;
random = new Random(1234);
}
public IndexingTest(String arg0) {
super(arg0);
}
public static void main(String[] args)
throws XMLDBException, ParserConfigurationException,
SAXException, IOException, ClassNotFoundException,
IllegalAccessException, InstantiationException {
System.setProperty("exist.initdb", "true");
IndexingTest tester = new IndexingTest("");
// tester.runTestrregularilyStructured(false);
tester.testIrregularilyStructured(true);
}
public void testIrregularilyStructured( )
throws XMLDBException, ParserConfigurationException, SAXException,
IOException, ClassNotFoundException, InstantiationException, IllegalAccessException
{
testIrregularilyStructured( true);
}
public void testIrregularilyStructured(boolean getContentAsDOM)
throws XMLDBException, ParserConfigurationException, SAXException, IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
Database database = null;
final String testName = "IrregularilyStructured";
startTime = System.currentTimeMillis();
try {
System.out.println("Running test " + testName + " ...");
// Tell eXist where conf.xml is :
// DWES #### use Configuration.getExistHome()
if ( EXIST_HOME != "" )
System.setProperty("exist.home", EXIST_HOME );
Class dbc = Class.forName("org.exist.xmldb.DatabaseImpl");
database = (Database) dbc.newInstance();
database.setProperty( "create-database", "true" );
DatabaseManager.registerDatabase(database);
Collection coll =
DatabaseManager.getCollection(baseURI, username, password);
XMLResource resource =
(XMLResource) coll.createResource(
name,
XMLResource.RESOURCE_TYPE);
Document doc =
DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.newDocument();
effectiveSiblingCount = populate(doc);
printTime();
resource.setContentAsDOM(doc);
printTime();
coll.storeResource(resource);
System.out.println("TEST> stored Resource " + name );
printTime();
coll.close();
coll = DatabaseManager.getCollection(baseURI, username, password);
resource = (XMLResource) coll.getResource(name);
System.out.println("TEST> retrieved Resource " + name );
printTime();
Node n;
if (getContentAsDOM) {
n = resource.getContentAsDOM();
} else {
String s = (String) resource.getContent();
byte[] bytes;
bytes = s.getBytes("UTF-8");
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
DocumentBuilder db =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
n = db.parse(bais);
}
System.out.println("getContentAsDOM: " + n.getNodeName());
Element documentElement = null;
if ( n instanceof Element ) {
documentElement = (Element)n;
} else if ( n instanceof Document ) {
documentElement = ((Document)n).getDocumentElement();
}
assertions(documentElement);
coll.removeResource(resource);
System.out.println("TEST> " + testName + " : PASSED");
} finally {
printTime();
if (database != null) {
Collection coll =
DatabaseManager.getCollection(
baseURI,
username,
password);
DatabaseManager.deregisterDatabase(database);
DatabaseInstanceManager dim =
(DatabaseInstanceManager) coll.getService(
"DatabaseInstanceManager",
"1.0");
dim.shutdown();
printTime();
}
}
}
private void printTime() {
System.out.println( "Current ellapsed time : " + ( System.currentTimeMillis() - startTime )/ 1000.f );
}
/** Assertions and output: */
private void assertions(Element documentElement) {
int computedSiblingCount = documentElement.getChildNodes().getLength();
int computedDepth = ((Element)deepBranch).getElementsByTagName("element").getLength();
int computedElementCount =
documentElement.getElementsByTagName("element").getLength();
System.out.println(" documentElement.getChildNodes().getLength(): " +
computedSiblingCount );
System.out.println(" documentElement.getElementsByTagName(\"element\").getLength(): " +
computedElementCount );
assertEquals("siblingCount", effectiveSiblingCount, computedSiblingCount );
assertEquals("depth", depth*arity + depth, computedDepth );
System.out.println("TEST> assertions PASSED");
printTime();
// dumpCatabaseContent(n);
}
/** This one provokes the Exception */
private int populate(Document doc) {
int childrenCount = addChildren (doc, siblingCount);
// Add a long fat branch at root's first child :
deepBranch = doc.getDocumentElement().getFirstChild();
effectiveDepth = addFatBranch( doc, deepBranch, depth, null);
System.out.println("TEST> populate() done.");
return childrenCount;
}
/** This one doesn't provoke the Exception */
private int populateOK(Document doc) {
int childrenCount = addChildren (doc, siblingCount);
// Add large branches at root's first and last children :
addBranch ( doc, doc.getDocumentElement().getFirstChild(), depth, null);
deepBranch = doc.getDocumentElement().getLastChild();
effectiveDepth = addBranch ( doc, deepBranch, depth, null);
Element documentElement = doc.getDocumentElement();
// Add (small) branches everywhere at level 1 :
int firstLevelWidth = doc.getDocumentElement().getChildNodes().getLength();
{
Node current = documentElement.getFirstChild();
for (int j = 0; j < firstLevelWidth - 1; j++) {
addBranch ( doc, current, 10, "branch");
current = current.getNextSibling();
}
}
// Add level 2 siblings everywhere at level 1 :
{
Node current = documentElement.getFirstChild();
for (int j = 0; j < firstLevelWidth - 1; j++) {
addChildren (current, arity, doc);
current = current.getNextSibling();
}
}
System.out.println("TEST> " + firstLevelWidth + " first Level elements populated.");
return childrenCount;
}
private int addBranch( Document doc, Node branchNode, int depth, String elementName ) {
int rdepth = 0;
if ( branchNode != null ) {
Node current = branchNode;
if ( elementName == null || elementName == "" )
elementName = "element";
if ( randomSizes )
rdepth = random.nextInt(depth);
else
rdepth = depth;
for (int j = 0; j < rdepth; j++) {
Element el = doc.createElement(elementName);
current.appendChild(el);
current = el;
}
}
return rdepth;
}
private int addFatBranch( Document doc, Node branchNode, int depth, String elementName ) {
int rdepth = 0;
if ( branchNode != null ) {
Node current = branchNode;
if ( elementName == null || elementName == "" )
elementName = "element";
if ( randomSizes )
rdepth = random.nextInt(depth);
else
rdepth = depth;
for (int j = 0; j < rdepth; j++) {
Element el = doc.createElement(elementName);
addChildren( el, arity, doc );
current.appendChild(el);
current = el;
}
}
return rdepth;
}
/**
* @param doc
* @param i
*/
private int addChildren(Document doc, int length ) {
Element rootElem = doc.createElement("root");
doc.appendChild(rootElem);
return addChildren(rootElem, length, doc);
}
private int addChildren( Node rootElem, int length, Document doc) {
int rlength = 0;
if ( rootElem != null ) {
if ( randomSizes )
rlength = random.nextInt(length);
else
rlength = length;
for (int j = 0; j < rlength; j++) {
Element el = doc.createElement("element");
rootElem.appendChild(el);
}
}
return rlength;
}
private void dumpCatabaseContent(Node n) {
try {
Transformer t = TransformerFactory.newInstance().newTransformer();
DOMSource source = new DOMSource(n);
SAXResult result = new SAXResult(new IndexingTest.SAXHandler());
t.transform(source, result);
} catch (Exception e) {
fail(e.getMessage());
}
}
class SAXHandler implements ContentHandler {
SAXHandler() {
}
public void characters(char[] ch, int start, int length) {
System.out.println(
"SAXHandler.characters("
+ new String(ch)
+ ", "
+ start
+ ", "
+ length
+ ")");
}
public void endDocument() {
System.out.println("SAXHandler.endDocument()");
}
public void endElement(
String namespaceURI,
String localName,
String qName) {
System.out.println(
"SAXHandler.endElement("
+ namespaceURI
+ ", "
+ localName
+ ", "
+ qName
+ ")");
}
public void endPrefixMapping(String prefix) {
System.out.println("SAXHandler.endPrefixMapping(" + prefix + ")");
}
public void ignorableWhitespace(char[] ch, int start, int length) {
System.out.println(
"SAXHandler.ignorableWhitespace("
+ new String(ch)
+ ", "
+ start
+ ", "
+ length
+ ")");
}
public void processingInstruction(String target, String data) {
System.out.println(
"SAXHandler.processingInstruction("
+ target
+ ", "
+ data
+ ")");
}
public void setDocumentLocator(Locator locator) {
System.out.println(
"SAXHandler.setDocumentLocator(" + locator + ")");
}
public void skippedEntity(String name) {
System.out.println("SAXHandler.skippedEntity(" + name + ")");
}
public void startDocument() {
System.out.println("SAXHandler.startDocument()");
}
public void startElement(
String namespaceURI,
String localName,
String qName,
Attributes atts) {
System.out.println(
"SAXHandler.startElement("
+ namespaceURI
+ ", "
+ localName
+ ", "
+ qName
+ ","
+ atts
+ ")");
}
public void startPrefixMapping(String prefix, String xuri) {
System.out.println(
"SAXHandler.startPrefixMapping(" + prefix + ", " + xuri + ")");
}
}
}