package org.exist.dom;
import java.io.StringReader;
import java.util.Iterator;
import org.exist.EXistException;
import org.exist.numbering.NodeId;
import org.exist.security.User;
import org.exist.security.xacml.AccessContext;
import org.exist.security.xacml.NullAccessContextException;
import org.exist.storage.BrokerPool;
import org.exist.storage.DBBroker;
import org.exist.util.OrderedLinkedList;
import org.exist.xquery.AnalyzeContextInfo;
import org.exist.xquery.Constants;
import org.exist.xquery.PathExpr;
import org.exist.xquery.XPathException;
import org.exist.xquery.XQueryContext;
import org.exist.xquery.parser.XQueryLexer;
import org.exist.xquery.parser.XQueryParser;
import org.exist.xquery.parser.XQueryTreeParser;
import org.exist.xquery.value.Item;
import org.exist.xquery.value.Sequence;
import org.exist.xquery.value.SequenceIterator;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import antlr.collections.AST;
public class SortedNodeSet extends AbstractNodeSet {
private PathExpr expr;
private OrderedLinkedList list = new OrderedLinkedList();
private String sortExpr;
private BrokerPool pool;
private User user = null;
private AccessContext accessCtx;
private SortedNodeSet() {}
public SortedNodeSet(BrokerPool pool, User user, String sortExpr, AccessContext accessCtx) {
this.sortExpr = sortExpr;
this.pool = pool;
this.user = user;
if(accessCtx == null)
throw new NullAccessContextException();
this.accessCtx = accessCtx;
}
public boolean isEmpty() {
return list.size() == 0;
}
public boolean hasOne() {
return list.size() == 1;
}
public void addAll(Sequence other) throws XPathException {
addAll(other.toNodeSet());
}
public void addAll(NodeSet other) {
long start = System.currentTimeMillis();
MutableDocumentSet docs = new DefaultDocumentSet();
for (Iterator i = other.iterator(); i.hasNext();) {
NodeProxy p = (NodeProxy)i.next();
docs.add(p.getDocument());
}
// TODO(pkaminsk2): why replicate XQuery.compile here?
DBBroker broker = null;
try {
broker = pool.get(user);
XQueryContext context = new XQueryContext(broker, accessCtx);
XQueryLexer lexer = new XQueryLexer(context, new StringReader(sortExpr));
XQueryParser parser = new XQueryParser(lexer);
XQueryTreeParser treeParser = new XQueryTreeParser(context);
parser.xpath();
if (parser.foundErrors()) {
//TODO : error ?
LOG.debug(parser.getErrorMessage());
}
AST ast = parser.getAST();
LOG.debug("generated AST: " + ast.toStringTree());
expr = new PathExpr(context);
treeParser.xpath(ast, expr);
if (treeParser.foundErrors()) {
LOG.debug(treeParser.getErrorMessage());
}
expr.analyze(new AnalyzeContextInfo());
for (SequenceIterator i = other.iterate(); i.hasNext();) {
NodeProxy p = (NodeProxy) i.nextItem();
IteratorItem item = new IteratorItem(broker, p, expr, docs, context);
list.add(item);
}
} catch (antlr.RecognitionException re) {
LOG.debug(re);
} catch (antlr.TokenStreamException tse) {
LOG.debug(tse);
} catch (EXistException e) {
LOG.debug("Exception during sort", e);
} catch (XPathException e) {
LOG.debug("Exception during sort", e);
} finally {
pool.release(broker);
}
LOG.debug(
"sort-expression found "
+ list.size()
+ " in "
+ (System.currentTimeMillis() - start)
+ "ms.");
}
public void addAll(NodeList other) {
if (!(other instanceof NodeSet))
throw new RuntimeException("not implemented!");
addAll((NodeSet) other);
}
public boolean contains(NodeProxy proxy) {
for (Iterator i = list.iterator(); i.hasNext();) {
NodeProxy p = ((IteratorItem) i.next()).proxy;
if (p.compareTo(proxy) == 0)
return true;
}
return false;
}
public NodeProxy get(int pos) {
final IteratorItem item = (IteratorItem) list.get(pos);
return item == null ? null : item.proxy;
}
public NodeProxy get(DocumentImpl doc, NodeId nodeId) {
NodeProxy proxy = new NodeProxy(doc, nodeId);
for (Iterator i = list.iterator(); i.hasNext();) {
NodeProxy p = ((IteratorItem) i.next()).proxy;
if (p.compareTo(proxy) == 0)
return p;
}
return null;
}
public NodeProxy get(NodeProxy proxy) {
for (Iterator i = list.iterator(); i.hasNext();) {
NodeProxy p = ((IteratorItem) i.next()).proxy;
if (p.compareTo(proxy) == 0)
return p;
}
return null;
}
public int getLength() {
return list.size();
}
//TODO : evaluate both semantics
public int getItemCount() {
return list.size();
}
public Node item(int pos) {
NodeProxy p = ((IteratorItem) list.get(pos)).proxy;
return p == null ? null : p.getDocument().getNode(p);
}
public Item itemAt(int pos) {
NodeProxy p = ((IteratorItem) list.get(pos)).proxy;
return p == null ? null : p;
}
public NodeSetIterator iterator() {
return new SortedNodeSetIterator(list.iterator());
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#iterate()
*/
public SequenceIterator iterate() throws XPathException {
return new SortedNodeSetIterator(list.iterator());
}
/* (non-Javadoc)
* @see org.exist.dom.AbstractNodeSet#unorderedIterator()
*/
public SequenceIterator unorderedIterator() throws XPathException {
return new SortedNodeSetIterator(list.iterator());
}
private final static class SortedNodeSetIterator implements NodeSetIterator, SequenceIterator {
Iterator pi;
public SortedNodeSetIterator(Iterator i) {
pi = i;
}
public boolean hasNext() {
return pi.hasNext();
}
public Object next() {
if (!pi.hasNext())
return null;
return ((IteratorItem) pi.next()).proxy;
}
public NodeProxy peekNode() {
return null;
}
/* (non-Javadoc)
* @see org.exist.xquery.value.SequenceIterator#nextItem()
*/
public Item nextItem() {
if (!pi.hasNext())
return null;
return ((IteratorItem) pi.next()).proxy;
}
public void remove() {
}
public void setPosition(NodeProxy proxy) {
throw new RuntimeException("NodeSetIterator.setPosition() is not supported by SortedNodeSetIterator");
}
}
private static final class IteratorItem extends OrderedLinkedList.Node {
NodeProxy proxy;
String value = null;
public IteratorItem(DBBroker broker, NodeProxy proxy, PathExpr expr, DocumentSet ndocs,
XQueryContext context) {
this.proxy = proxy;
try {
Sequence seq = expr.eval(proxy);
StringBuilder buf = new StringBuilder();
OrderedLinkedList strings = new OrderedLinkedList();
Item item;
for(SequenceIterator i = seq.iterate(); i.hasNext(); ) {
item = i.nextItem();
strings.add(new OrderedLinkedList.SimpleNode(item.getStringValue().toUpperCase()));
}
for (Iterator j = strings.iterator(); j.hasNext();)
buf.append(((OrderedLinkedList.SimpleNode) j.next()).getData());
value = buf.toString();
} catch (XPathException e) {
LOG.warn(e.getMessage(), e);
}
}
public int compareTo(OrderedLinkedList.Node other) {
IteratorItem o = (IteratorItem) other;
if (value == null)
return o.value == null ? Constants.EQUAL : Constants.SUPERIOR;
if (o.value == null)
return value == null ? Constants.EQUAL : Constants.INFERIOR;
return value.compareTo(o.value);
}
public boolean equals(OrderedLinkedList.Node other) {
IteratorItem o = (IteratorItem) other;
return value.equals(o.value);
}
}
/* (non-Javadoc)
* @see org.exist.dom.NodeSet#add(org.exist.dom.NodeProxy)
*/
public void add(NodeProxy proxy) {
LOG.info("Called SortedNodeSet.add()");
}
}