/*
* eXist Open Source Native XML Database
* Copyright (C) 2001-2015 The eXist Project
* http://exist-db.org
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package org.exist.indexing.lucene;
import static org.exist.util.PropertiesBuilder.propertiesBuilder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Path;
import java.util.*;
import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import org.exist.EXistException;
import org.exist.Indexer;
import org.exist.TestUtils;
import org.exist.collections.Collection;
import org.exist.collections.CollectionConfigurationManager;
import org.exist.collections.CollectionConfigurationException;
import org.exist.collections.IndexInfo;
import org.exist.collections.triggers.TriggerException;
import org.exist.dom.QName;
import org.exist.dom.persistent.DefaultDocumentSet;
import org.exist.dom.persistent.DocumentSet;
import org.exist.dom.persistent.MutableDocumentSet;
import org.exist.indexing.OrderedValuesIndex;
import org.exist.indexing.QNamedKeysIndex;
import org.exist.security.PermissionDeniedException;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.storage.ElementValue;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import org.exist.test.ExistEmbeddedServer;
import org.exist.test.TestConstants;
import org.exist.util.*;
import org.exist.xmldb.XmldbURI;
import org.exist.xquery.XQuery;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.CompiledXQuery;
import org.exist.xquery.XPathException;
import org.exist.xquery.value.Sequence;
import org.exist.xupdate.Modification;
import org.exist.xupdate.XUpdateProcessor;
import org.junit.*;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class LuceneIndexTest {
protected static String XUPDATE_START =
"<xu:modifications version=\"1.0\" xmlns:xu=\"http://www.xmldb.org/xupdate\">";
protected static String XUPDATE_END =
"</xu:modifications>";
private static final String XML1 =
"<section>" +
" <head>The title in big letters</head>" +
" <p rend=\"center\">A simple paragraph with <hi>just</hi> text in it.</p>" +
" <p rend=\"right\">paragraphs with <span>mix</span><span>ed</span> content are <span>danger</span>ous.</p>" +
"</section>";
private static final String XML2 =
"<test>" +
" <item id='1' attr='attribute'><description>Chair</description></item>" +
" <item id='2'><description>Table</description>\n<condition>good</condition></item>" +
" <item id='3'><description>Cabinet</description>\n<condition>bad</condition></item>" +
"</test>";
private static final String XML3 =
"<section>" +
" <head>TITLE IN UPPERCASE LETTERS</head>" +
" <p>UPPERCASE PARAGRAPH</p>" +
"</section>";
private static final String XML4 =
"<test><a>A X</a><b><c>B X</c> C</b></test>";
private static final String XML5 =
"<article>" +
" <head>The <b>title</b>of it</head>" +
" <p>A simple paragraph with <hi>highlighted</hi> text <note>and a note</note> " +
" in it.</p>" +
" <p>Paragraphs with <s>mix</s><s>ed</s> content are <s>danger</s>ous.</p>" +
" <p><note1>ignore</note1> <s2>warn</s2>ings</p>" +
"</article>";
private static final String XML6 =
"<a>" +
" <b>AAA</b>" +
" <c>AAA</c>" +
" <b>AAA</b>" +
"</a>";
private static final String XML7 =
"<section>" +
" <head>Query Test</head>" +
" <p>Eine wunderbare Heiterkeit hat meine ganze Seele eingenommen, gleich den " +
" süßen Frühlingsmorgen, die ich mit ganzem Herzen genieße. Ich bin allein und " +
" freue mich meines Lebens in dieser Gegend, die für solche Seelen geschaffen " +
" ist wie die meine. Ich bin so glücklich, mein Bester, so ganz in dem Gefühle " +
" von ruhigem Dasein versunken, daß meine Kunst darunter leidet.</p>" +
"</section>";
private static final String XML8 =
"<a>" +
" <b att='att on b1'>AAA on b1</b>" +
" <b att='att on b2' attr='attr on b2'>AAA on b2</b>" +
" <bb><b att='att on b3' attr='attr on b3'>AAA on b3</b></bb>" +
" <c att='att on c1'>AAA on c1</c>" +
" <c>AAA on c2</c>" +
"</a>";
private static final String XML9 =
"<TEI xmlns=\"http://www.tei-c.org/ns/1.0\">" +
" <body>" +
" <p>erste aus haus maus zaus yaus raus qaus leisten</p>" +
" <p>ausser aus</p>" +
" <p>auf boden</p>" +
" </body>" +
"</TEI>";
private static final String COLLECTION_CONFIG1 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index>" +
" <lucene>" +
" <analyzer class=\"org.apache.lucene.analysis.core.SimpleAnalyzer\"/>" +
" <text match=\"/section/p\"/>" +
" <text qname=\"head\"/>" +
" <text qname=\"@rend\"/>" +
" <text qname=\"hi\"/>" +
" <text qname=\"LINE\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG2 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index>" +
" <lucene>" +
" <text qname=\"item\"/>" +
" <text match=\"//description\"/>" +
" <text qname=\"condition\"/>" +
" <text qname=\"@attr\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG3 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index>" +
" <lucene>" +
" <analyzer id=\"whitespace\" class=\"org.apache.lucene.analysis.core.WhitespaceAnalyzer\"/>" +
" <text match=\"/section/head\" analyzer=\"whitespace\"/>" +
" <text match=\"//p\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG4 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index>" +
" <lucene>" +
" <text match=\"/test/a\"/>" +
" <text match=\"/test/b/*\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG5 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index xmlns:tei=\"http://www.tei-c.org/ns/1.0\">" +
" <lucene>" +
" <text qname=\"article\">" +
" <ignore qname=\"note\"/>" +
" <inline qname=\"s\"/>" +
" </text>" +
" <text qname=\"p\">" +
" <ignore qname=\"note\"/>" +
" <inline qname=\"s\"/>" +
" </text>" +
" <text qname=\"head\"/>" +
" <ignore qname=\"note1\"/>" +
" <inline qname=\"s2\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG6 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index xmlns:tei=\"http://www.tei-c.org/ns/1.0\">" +
" <lucene>" +
" <text qname=\"b\"/>" +
" <text qname=\"c\" boost=\"2.0\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG7 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index xmlns:tei=\"http://www.tei-c.org/ns/1.0\">" +
" <lucene>" +
" <text qname='c'>" +
" <has-attribute qname='att' boost='30'/>" +
" </text>" +
" <text qname='b' boost='5'>" +
" <match-attribute qname='att' value='att on b2' boost='30'/>" +
" <match-attribute qname='attr' value='attr on b3' boost='5'/>" +
" <has-attribute qname='attr' boost='15'/>" +
" </text>" +
" <text qname='@att'>" +
" <match-sibling-attribute qname='attr' value='attr on b2' boost='2'/>" +
" <has-sibling-attribute qname='attr' boost='2'/>" +
" </text>" +
" </lucene>" +
" </index>" +
"</collection>";
private static final String COLLECTION_CONFIG8 =
"<collection xmlns=\"http://exist-db.org/collection-config/1.0\">" +
" <index xmlns:tei=\"http://www.tei-c.org/ns/1.0\">" +
" <lucene>" +
" <analyzer class=\"org.apache.lucene.analysis.standard.StandardAnalyzer\"/>" +
" <text qname=\"tei:p\"/>" +
" </lucene>" +
" </index>" +
"</collection>";
private static Collection root;
private Boolean savedConfig;
@Test
public void simpleQueries() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG1, XML1, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
checkIndex(docs, broker, new QName[] { new QName("head") }, "title", 1);
final Occurrences[] o = checkIndex(docs, broker, new QName[]{new QName("p")}, "with", 1);
assertEquals(2, o[0].getOccurrences());
checkIndex(docs, broker, new QName[] { new QName("hi") }, "just", 1);
checkIndex(docs, broker, null, "in", 1);
final QName attrQN = new QName("rend", XMLConstants.NULL_NS_URI, ElementValue.ATTRIBUTE);
checkIndex(docs, broker, new QName[] { attrQN }, null, 2);
checkIndex(docs, broker, new QName[] { attrQN }, "center", 1);
checkIndex(docs, broker, new QName[] { attrQN }, "right", 1);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "/section[ft:query(p, 'content')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(p/@rend, 'center')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(hi, 'just')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(p/*, 'just')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(head/*, 'just')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
}
}
@Test
public void configuration() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG4, XML4, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
checkIndex(docs, broker, new QName[] { new QName("a") }, "x", 1);
checkIndex(docs, broker, new QName[] { new QName("c") }, "x", 1);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "/test[ft:query(a, 'x')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/test[ft:query(.//c, 'x')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/test[ft:query(b, 'x')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
}
}
@Test
public void inlineAndIgnore() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG5, XML5, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
checkIndex(docs, broker, new QName[] { new QName("head") }, "title", 1);
checkIndex(docs, broker, new QName[] { new QName("p") }, "simple", 1);
checkIndex(docs, broker, new QName[] { new QName("p") }, "mixed", 1);
checkIndex(docs, broker, new QName[] { new QName("p") }, "dangerous", 1);
checkIndex(docs, broker, new QName[] { new QName("p") }, "note", 0);
checkIndex(docs, broker, new QName[] { new QName("p") }, "ignore", 0);
checkIndex(docs, broker, new QName[]{new QName("p")}, "warnings", 1);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "/article[ft:query(head, 'title')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'highlighted')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'mixed')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'mix')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'dangerous')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'ous')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'danger')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(p, 'note')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'highlighted')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'mixed')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'dangerous')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'warnings')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'danger')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'note')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
seq = xquery.execute(broker, "/article[ft:query(., 'ignore')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
}
}
@Test
public void attributeMatch() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException, ParserConfigurationException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG7, XML8, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "for $a in ft:query((//b|//c), 'AAA') order by ft:score($a) descending return xs:string($a)", null);
assertNotNull(seq);
assertEquals(5, seq.getItemCount());
assertEquals("AAA on b2", seq.itemAt(0).getStringValue());
assertEquals("AAA on c1", seq.itemAt(1).getStringValue());
assertEquals("AAA on b3", seq.itemAt(2).getStringValue());
assertEquals("AAA on b1", seq.itemAt(3).getStringValue());
assertEquals("AAA on c2", seq.itemAt(4).getStringValue());
// path: /a/b
seq = xquery.execute(broker, "for $a in ft:query(/a/b, 'AAA') order by ft:score($a) descending return xs:string($a)", null);
assertNotNull(seq);
assertEquals(2, seq.getItemCount());
assertEquals("AAA on b2", seq.itemAt(0).getStringValue());
assertEquals("AAA on b1", seq.itemAt(1).getStringValue());
seq = xquery.execute(broker, "for $a in ft:query(//@att, 'att') order by ft:score($a) descending return xs:string($a)", null);
assertNotNull(seq);
assertEquals(4, seq.getItemCount());
assertEquals("att on b2", seq.itemAt(0).getStringValue());
assertEquals("att on b3", seq.itemAt(1).getStringValue());
assertEquals("att on b1", seq.itemAt(2).getStringValue());
assertEquals("att on c1", seq.itemAt(3).getStringValue());
// modify with xupdate and check if boosts are updated accordingly
final XUpdateProcessor proc = new XUpdateProcessor(broker, docs);
assertNotNull(proc);
proc.setBroker(broker);
proc.setDocumentSet(docs);
// remove 'att' attribute from first c element: it gets no boost
// also append an 'att' attribute on second c element which will
// make the two switch order in the result sequence.
String xupdate =
XUPDATE_START +
" <xu:remove select=\"//c[1]/@att\"/>" +
" <xu:append select=\"//c[2]\"><xu:attribute name=\"att\">att on c2</xu:attribute></xu:append>" +
XUPDATE_END;
final Modification[] modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
modifications[1].process(transaction);
proc.reset();
transact.commit(transaction);
seq = xquery.execute(broker, "for $a in ft:query((//b|//c), 'AAA') order by ft:score($a) descending return xs:string($a)", null);
assertNotNull(seq);
assertEquals(5, seq.getItemCount());
assertEquals("AAA on b2", seq.itemAt(0).getStringValue());
assertEquals("AAA on c2", seq.itemAt(1).getStringValue());
assertEquals("AAA on b3", seq.itemAt(2).getStringValue());
assertEquals("AAA on b1", seq.itemAt(3).getStringValue());
assertEquals("AAA on c1", seq.itemAt(4).getStringValue());
}
}
@Test
public void boosts() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
configureAndStore(COLLECTION_CONFIG6, XML6, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "for $a in ft:query((//b|//c), 'AAA') " +
"order by ft:score($a) descending return $a/local-name(.)", null);
assertNotNull(seq);
assertEquals(3, seq.getItemCount());
assertEquals("c", seq.getStringValue());
}
}
@Test
public void queryTranslation() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
configureAndStore(COLLECTION_CONFIG1, XML7, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
final XQueryContext context = new XQueryContext(broker.getBrokerPool());
final CompiledXQuery compiled = xquery.compile(broker, context, "declare variable $q external; " +
"ft:query(//p, util:parse($q)/query)");
context.declareVariable("q", "<query><term>heiterkeit</term></query>");
Sequence seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <term>heiterkeit</term><term>blablabla</term>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <term occur='should'>heiterkeit</term><term occur='should'>blablabla</term>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <term occur='must'>heiterkeit</term><term occur='must'>blablabla</term>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <term occur='must'>heiterkeit</term><term occur='not'>herzen</term>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <phrase occur='must'>wunderbare heiterkeit</phrase><term occur='must'>herzen</term>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <phrase slop='5'>heiterkeit seele eingenommen</phrase>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
// phrase with wildcards
context.declareVariable("q",
"<query>" +
" <phrase slop='5'><term>heiter*</term><term>se?nnnle*</term></phrase>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <wildcard>?eiter*</wildcard>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <fuzzy max-edits='2'>selee</fuzzy>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <bool>" +
" <fuzzy occur='must' max-edits='2'>selee</fuzzy>" +
" <wildcard occur='should'>bla*</wildcard>" +
" </bool>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <regex>heit.*keit</regex>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
context.declareVariable("q",
"<query>" +
" <phrase><term>wunderbare</term><regex>heit.*keit</regex></phrase>" +
"</query>");
seq = xquery.execute(broker, compiled, null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
}
}
@Test
public void analyzers() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG3, XML3, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
checkIndex(docs, broker, new QName[] { new QName("head") }, "TITLE", 1);
checkIndex(docs, broker, new QName[] { new QName("p") }, "uppercase", 1);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "/section[ft:query(p, 'UPPERCASE')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(head, 'TITLE')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
seq = xquery.execute(broker, "/section[ft:query(head, 'title')]", null);
assertNotNull(seq);
assertEquals(0, seq.getItemCount());
}
}
@Test
public void MultiTermQueryRewriteMethod() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
configureAndStore(COLLECTION_CONFIG8, XML9, "test.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "declare namespace tei=\"http://www.tei-c.org/ns/1.0\";" +
" for $expr in (\"au*\", \"ha*\", \"ma*\", \"za*\", \"ya*\", \"ra*\", \"qa*\")" +
" let $query := <query><wildcard>{$expr}</wildcard></query>" +
" return for $hit in //tei:p[ft:query(., $query)]" +
" return util:expand($hit)//exist:match", null);
assertNotNull(seq);
assertEquals(10, seq.getItemCount());
assertEquals("aus", seq.itemAt(0).getStringValue());
seq = xquery.execute(broker, "declare namespace tei=\"http://www.tei-c.org/ns/1.0\";" +
" for $expr in (\"ha*\", \"ma*\")" +
" let $query := <query><wildcard>{$expr}</wildcard></query>" +
" return for $hit in //tei:p[ft:query(., $query)]" +
" return util:expand($hit)//exist:match", null);
assertNotNull(seq);
assertEquals(2 , seq.getItemCount());
assertEquals("haus", seq.itemAt(0).getStringValue());
}
}
@Test
public void dropSingleDoc() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG1, XML1, "dropDocument.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
root.removeXMLResource(transaction, broker, XmldbURI.create("dropDocument.xml"));
transact.commit(transaction);
checkIndex(docs, broker, null, null, 0);
}
}
@Test
public void dropDocuments() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
configureAndStore(COLLECTION_CONFIG1, TestUtils.shakespeareSamples());
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
try(final Txn transaction = transact.beginTransaction()) {
Sequence seq = xquery.execute(broker, "//LINE[ft:query(., 'bark')]", null);
assertNotNull(seq);
assertEquals(6, seq.getItemCount());
root.removeXMLResource(transaction, broker, XmldbURI.create("r_and_j.xml"));
transact.commit(transaction);
seq = xquery.execute(broker, "//LINE[ft:query(., 'bark')]", null);
assertNotNull(seq);
assertEquals(3, seq.getItemCount());
}
try(final Txn transaction = transact.beginTransaction()) {
root.removeXMLResource(transaction, broker, XmldbURI.create("hamlet.xml"));
transact.commit(transaction);
Sequence seq = xquery.execute(broker, "//LINE[ft:query(., 'bark')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
}
}
}
@Test
public void removeCollection() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG1, TestUtils.shakespeareSamples());
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "//SPEECH[ft:query(LINE, 'love')]", null);
assertNotNull(seq);
assertEquals(166, seq.getItemCount());
broker.removeCollection(transaction, root);
root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI);
assertNotNull(root);
broker.saveCollection(transaction, root);
transact.commit(transaction);
root = null;
checkIndex(docs, broker, null, null, 0);
}
}
@Test
public void reindex() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG1, XML1, "dropDocument.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {
broker.reindexCollection(TestConstants.TEST_COLLECTION_URI);
checkIndex(docs, broker, new QName[] { new QName("head") }, "title", 1);
final Occurrences[] o = checkIndex(docs, broker, new QName[]{new QName("p")}, "with", 1);
assertEquals(2, o[0].getOccurrences());
checkIndex(docs, broker, new QName[] { new QName("hi") }, "just", 1);
checkIndex(docs, broker, null, "in", 1);
final QName attrQN = new QName("rend", XMLConstants.NULL_NS_URI, ElementValue.ATTRIBUTE);
checkIndex(docs, broker, new QName[] { attrQN }, null, 2);
checkIndex(docs, broker, new QName[] { attrQN }, "center", 1);
}
}
/**
* Remove nodes from different levels of the tree and check if the index is
* correctly updated.
*/
@Test
public void xupdateRemove() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException, ParserConfigurationException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG2, XML2, "xupdate.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 1);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 2);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "//item[ft:query(description, 'chair')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
final XUpdateProcessor proc = new XUpdateProcessor(broker, docs);
assertNotNull(proc);
proc.setBroker(broker);
proc.setDocumentSet(docs);
String xupdate =
XUPDATE_START +
" <xu:remove select=\"//item[@id='2']/condition\"/>" +
XUPDATE_END;
Modification[] modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 1);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 4);
checkIndex(docs, broker, new QName[] { new QName("condition") }, "good", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "good", 0);
Occurrences o[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "table", 1);
assertEquals("table", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "cabinet", 1);
assertEquals("cabinet", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "table", 1);
assertEquals("table", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "cabinet", 1);
assertEquals("cabinet", o[0].getTerm());
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:remove select=\"//item[@id='3']/description/text()\"/>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:remove select=\"//item[@id='1']\"/>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
o = checkIndex(docs, broker, new QName[] { new QName("description") }, null, 1);
assertEquals("table", o[0].getTerm());
checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "chair", 0);
transact.commit(transaction);
}
}
/**
* Remove nodes from different levels of the tree and check if the index is
* correctly updated.
*/
@Test
public void xupdateInsert() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException, ParserConfigurationException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG2, XML2, "xupdate.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final Occurrences occur[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 1);
assertEquals("chair", occur[0].getTerm());
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "//item[ft:query(description, 'chair')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
// Append to root node
final XUpdateProcessor proc = new XUpdateProcessor(broker, docs);
assertNotNull(proc);
proc.setBroker(broker);
proc.setDocumentSet(docs);
String xupdate =
XUPDATE_START +
" <xu:append select=\"/test\">" +
" <item id='4'><description>Armchair</description> <condition>bad</condition></item>" +
" </xu:append>" +
XUPDATE_END;
Modification[] modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
Occurrences o[] = checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 2);
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 4);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 6);
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "bad", 1);
assertEquals("bad", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "armchair", 1);
assertEquals("armchair", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "bad", 1);
assertEquals("bad", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "armchair", 1);
assertEquals("armchair", o[0].getTerm());
// Insert before top element
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:insert-before select=\"//item[@id = '1']\">" +
" <item id='0'><description>Wheelchair</description> <condition>poor</condition></item>" +
" </xu:insert-before>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 5);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 8);
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "poor", 1);
assertEquals("poor", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "wheelchair", 1);
assertEquals("wheelchair", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "poor", 1);
assertEquals("poor", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "wheelchair", 1);
assertEquals("wheelchair", o[0].getTerm());
// Insert after element
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:insert-after select=\"//item[@id = '1']\">" +
" <item id='1.1'><description>refrigerator</description> <condition>perfect</condition></item>" +
" </xu:insert-after>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 4);
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 6);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 10);
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "perfect", 1);
assertEquals("perfect", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "refrigerator", 1);
assertEquals("refrigerator", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "perfect", 1);
assertEquals("perfect", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "refrigerator", 1);
assertEquals("refrigerator", o[0].getTerm());
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:insert-after select=\"//item[@id = '1']/description\">" +
" <condition>average</condition>" +
" </xu:insert-after>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 5);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 11);
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "average", 1);
assertEquals("average", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "average", 1);
assertEquals("average", o[0].getTerm());
// Insert before nested element
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:insert-before select=\"//item[@id = '1']/description\">" +
" <condition>awesome</condition>" +
" </xu:insert-before>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 6);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 12);
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "awesome", 1);
assertEquals("awesome", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "awesome", 1);
assertEquals("awesome", o[0].getTerm());
// Overwrite attribute
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:append select=\"//item[@id = '1']\">" +
" <xu:attribute name=\"attr\">abc</xu:attribute>" +
" </xu:append>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
QName qnattr[] = { new QName("attr", XMLConstants.NULL_NS_URI, XMLConstants.DEFAULT_NS_PREFIX, ElementValue.ATTRIBUTE) };
o = checkIndex(docs, broker, qnattr, null, 1);
assertEquals("abc", o[0].getTerm());
checkIndex(docs, broker, qnattr, "attribute", 0);
transact.commit(transaction);
}
}
@Test
public void xupdateUpdate() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException, ParserConfigurationException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG2, XML2, "xupdate.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final Occurrences occur[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 1);
assertEquals("chair", occur[0].getTerm());
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "//item[ft:query(description, 'chair')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
// Update element content
final XUpdateProcessor proc = new XUpdateProcessor(broker, docs);
proc.setBroker(broker);
proc.setDocumentSet(docs);
String xupdate =
XUPDATE_START +
" <xu:update select=\"//item[@id = '1']/description\">wardrobe</xu:update>" +
XUPDATE_END;
Modification[] modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "chair", 0);
Occurrences o[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "wardrobe", 1);
assertEquals("wardrobe", o[0].getTerm());
// Update text node
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:update select=\"//item[@id = '1']/description/text()\">Wheelchair</xu:update>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
checkIndex(docs, broker, new QName[] { new QName("description") }, "wardrobe", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "wardrobe", 0);
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "wheelchair", 1);
assertEquals("wheelchair", o[0].getTerm());
// Update attribute value
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
" <xu:update select=\"//item[@id = '1']/@attr\">abc</xu:update>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
final QName qnattr[] = { new QName("attr", XMLConstants.NULL_NS_URI, XMLConstants.DEFAULT_NS_PREFIX, ElementValue.ATTRIBUTE) };
o = checkIndex(docs, broker, qnattr, null, 1);
assertEquals("abc", o[0].getTerm());
checkIndex(docs, broker, qnattr, "attribute", 0);
transact.commit(transaction);
}
}
@Test
public void xupdateReplace() throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException, XPathException, ParserConfigurationException {
final DocumentSet docs = configureAndStore(COLLECTION_CONFIG2, XML2, "xupdate.xml");
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final Occurrences occur[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 1);
assertEquals("chair", occur[0].getTerm());
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 5);
final XQuery xquery = pool.getXQueryService();
assertNotNull(xquery);
Sequence seq = xquery.execute(broker, "//item[ft:query(description, 'chair')]", null);
assertNotNull(seq);
assertEquals(1, seq.getItemCount());
final XUpdateProcessor proc = new XUpdateProcessor(broker, docs);
assertNotNull(proc);
proc.setBroker(broker);
proc.setDocumentSet(docs);
String xupdate =
XUPDATE_START +
"<xu:replace select=\"//item[@id = '1']\">" +
"<item id='4'><description>Wheelchair</description> <condition>poor</condition></item>" +
"</xu:replace>" +
XUPDATE_END;
Modification[] modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("condition") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 6);
checkIndex(docs, broker, new QName[] { new QName("description") }, "chair", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "chair", 0);
Occurrences o[] = checkIndex(docs, broker, new QName[] { new QName("description") }, "wheelchair", 1);
assertEquals("wheelchair", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("condition") }, "poor", 1);
assertEquals("poor", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "wheelchair", 1);
assertEquals("wheelchair", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "poor", 1);
assertEquals("poor", o[0].getTerm());
proc.setBroker(broker);
proc.setDocumentSet(docs);
xupdate =
XUPDATE_START +
"<xu:replace select=\"//item[@id = '4']/description\">" +
"<description>Armchair</description>" +
"</xu:replace>" +
XUPDATE_END;
modifications = proc.parse(new InputSource(new StringReader(xupdate)));
assertNotNull(modifications);
modifications[0].process(transaction);
proc.reset();
checkIndex(docs, broker, new QName[] { new QName("description") }, null, 3);
checkIndex(docs, broker, new QName[] { new QName("item") }, null, 6);
checkIndex(docs, broker, new QName[] { new QName("description") }, "wheelchair", 0);
checkIndex(docs, broker, new QName[] { new QName("item") }, "wheelchair", 0);
o = checkIndex(docs, broker, new QName[] { new QName("description") }, "armchair", 1);
assertEquals("armchair", o[0].getTerm());
o = checkIndex(docs, broker, new QName[] { new QName("item") }, "armchair", 1);
assertEquals("armchair", o[0].getTerm());
transact.commit(transaction);
}
}
private DocumentSet configureAndStore(final String configuration, final String data, final String docName) throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException {
final MutableDocumentSet docs = new DefaultDocumentSet();
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
if (configuration != null) {
final CollectionConfigurationManager mgr = pool.getConfigurationManager();
mgr.addConfiguration(transaction, broker, root, configuration);
}
final IndexInfo info = root.validateXMLResource(transaction, broker, XmldbURI.create(docName), data);
assertNotNull(info);
root.store(transaction, broker, info, data);
docs.add(info.getDocument());
transact.commit(transaction);
}
return docs;
}
private DocumentSet configureAndStore(String configuration, Path directory) throws EXistException, CollectionConfigurationException, PermissionDeniedException, SAXException, TriggerException, LockException, IOException {
final MutableDocumentSet docs = new DefaultDocumentSet();
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
if (configuration != null) {
final CollectionConfigurationManager mgr = pool.getConfigurationManager();
mgr.addConfiguration(transaction, broker, root, configuration);
}
final List<Path> files = FileUtils.list(directory);
final MimeTable mimeTab = MimeTable.getInstance();
for (final Path f : files) {
MimeType mime = mimeTab.getContentTypeFor(FileUtils.fileName(f));
if(mime != null && mime.isXMLType()) {
InputSource is = new FileInputSource(f);
final IndexInfo info = root.validateXMLResource(transaction, broker, XmldbURI.create(FileUtils.fileName(f)), is);
assertNotNull(info);
is = new FileInputSource(f);
root.store(transaction, broker, info, is);
docs.add(info.getDocument());
}
}
transact.commit(transaction);
}
return docs;
}
private Occurrences[] checkIndex(final DocumentSet docs, final DBBroker broker, final QName[] qn, final String term, final int expected) {
final LuceneIndexWorker index = (LuceneIndexWorker)broker.getIndexController().getWorkerByIndexId(LuceneIndex.ID);
final Map<String, Object> hints = new HashMap<>();
if (term != null) {
hints.put(OrderedValuesIndex.START_VALUE, term);
}
if (qn != null && qn.length > 0) {
final List<QName> qnlist = new ArrayList<>(qn.length);
qnlist.addAll(Arrays.asList(qn));
hints.put(QNamedKeysIndex.QNAMES_KEY, qnlist);
}
final XQueryContext context = new XQueryContext(broker.getBrokerPool());
final Occurrences[] occur = index.scanIndex(context, docs, null, hints);
assertEquals(expected, occur.length);
return occur;
}
@Before
public void setup() throws EXistException, PermissionDeniedException, IOException, TriggerException {
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI);
assertNotNull(root);
broker.saveCollection(transaction, root);
transact.commit(transaction);
final Configuration config = BrokerPool.getInstance().getConfiguration();
savedConfig = (Boolean) config.getProperty(Indexer.PROPERTY_PRESERVE_WS_MIXED_CONTENT);
config.setProperty(Indexer.PROPERTY_PRESERVE_WS_MIXED_CONTENT, Boolean.TRUE);
}
}
@After
public void cleanup() throws EXistException, PermissionDeniedException, IOException, TriggerException {
final BrokerPool pool = existEmbeddedServer.getBrokerPool();
final TransactionManager transact = pool.getTransactionManager();
try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()));
final Txn transaction = transact.beginTransaction()) {
final Collection collConfig = broker.getOrCreateCollection(transaction,
XmldbURI.create(XmldbURI.CONFIG_COLLECTION + "/db"));
assertNotNull(collConfig);
broker.removeCollection(transaction, collConfig);
if (root != null) {
assertNotNull(root);
broker.removeCollection(transaction, root);
}
transact.commit(transaction);
final Configuration config = BrokerPool.getInstance().getConfiguration();
config.setProperty(Indexer.PROPERTY_PRESERVE_WS_MIXED_CONTENT, savedConfig);
}
}
@ClassRule
public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(
propertiesBuilder()
.set(Indexer.PROPERTY_SUPPRESS_WHITESPACE, "none")
.put(Indexer.PRESERVE_WS_MIXED_CONTENT_ATTRIBUTE, Boolean.TRUE)
.build(),
true,
false);
@AfterClass
public static void cleanupDb() {
TestUtils.cleanupDB();
}
}