4848import antlr .RecognitionException ;
4949import antlr .TokenStreamException ;
5050import antlr .collections .AST ;
51+ import com .evolvedbinary .j8cu .list .linked .BoundedDoublyLinkedList ;
52+ import com .evolvedbinary .j8cu .list .linked .OrderedDoublyLinkedList ;
5153import org .exist .EXistException ;
5254import org .exist .numbering .NodeId ;
5355import org .exist .security .Subject ;
5456import org .exist .storage .BrokerPool ;
5557import org .exist .storage .DBBroker ;
56- import org .exist .util .OrderedLinkedList ;
5758import org .exist .xquery .*;
5859import org .exist .xquery .parser .XQueryLexer ;
5960import org .exist .xquery .parser .XQueryParser ;
6465import org .w3c .dom .Node ;
6566import org .w3c .dom .NodeList ;
6667
68+ import javax .annotation .Nullable ;
6769import java .io .StringReader ;
68- import java .util .Iterator ;
69- import java . util . NoSuchElementException ;
70- import java . util . Optional ;
70+ import java .util .* ;
71+
72+ import static com . evolvedbinary . j8cu . list . linked . Bounded . bound ;
7173
7274
7375public class SortedNodeSet extends AbstractNodeSet {
7476
75- private final OrderedLinkedList list = new OrderedLinkedList ( );
77+ private final BoundedDoublyLinkedList < IteratorItem > list = bound ( new OrderedDoublyLinkedList < IteratorItem >(), Long . MAX_VALUE );
7678
7779 private final String sortExpr ;
7880 private final BrokerPool pool ;
@@ -86,7 +88,7 @@ public SortedNodeSet(final BrokerPool pool, final Subject user, final String sor
8688
8789 @ Override
8890 public boolean isEmpty () {
89- return list .size () == 0 ;
91+ return list .isEmpty () ;
9092 }
9193
9294 @ Override
@@ -120,37 +122,64 @@ public void addAll(final NodeSet other) {
120122 }
121123 final AST ast = parser .getAST ();
122124 LOG .debug ("generated AST: {}" , ast .toStringTree ());
123- final PathExpr expr = new PathExpr (context );
124- treeParser .xpath (ast , expr );
125- if (treeParser .foundErrors ()) {
126- LOG .debug (treeParser .getErrorMessage ());
127- }
128- expr .analyze (new AnalyzeContextInfo ());
129- for (final SequenceIterator i = other .iterate (); i .hasNext (); ) {
130- final NodeProxy p = (NodeProxy ) i .nextItem ();
131- final IteratorItem item = new IteratorItem (p , expr );
132- list .add (item );
125+ final PathExpr sortExpression = new PathExpr (context );
126+ try {
127+ treeParser .xpath (ast , sortExpression );
128+ if (treeParser .foundErrors ()) {
129+ LOG .debug (treeParser .getErrorMessage ());
130+ }
131+ sortExpression .analyze (new AnalyzeContextInfo ());
132+ for (final SequenceIterator i = other .iterate (); i .hasNext (); ) {
133+ final NodeProxy p = (NodeProxy ) i .nextItem ();
134+ final IteratorItem item = createIteratorItem (sortExpression , p );
135+ list .add (item );
136+ }
137+ } finally {
138+ sortExpression .getContext ().runCleanupTasks ();
139+ sortExpression .getContext ().reset ();
133140 }
134141 } catch (final RecognitionException | TokenStreamException re ) {
135142 LOG .debug (re ); //TODO : throw exception ! -pb
136143 } catch (final EXistException | XPathException e ) {
137- LOG .debug ("Exception during sort" , e ); //TODO : throw exception ! -pb
144+ LOG .debug ("Exception during sort: " + e . getMessage () , e ); //TODO : throw exception ! -pb
138145 }
139146 LOG .debug ("sort-expression found {} in {}ms." , list .size (), System .currentTimeMillis () - start );
140147 }
141148
149+ private IteratorItem createIteratorItem (final Expression sortExpression , final NodeProxy nodeProxy ) throws XPathException {
150+ final Sequence seq = sortExpression .eval (nodeProxy , null );
151+
152+ // copy string values of items into an array
153+ int sbCapacity = 0 ;
154+ final String [] strings = new String [seq .getItemCount ()];
155+ for (int i = 0 ; i < strings .length ; i ++) {
156+ final String strItem = seq .itemAt (i ).getStringValue ().toUpperCase ();
157+ sbCapacity += strItem .length ();
158+ strings [i ] = strItem ;
159+ }
160+
161+ // sort and then concatenate strings
162+ Arrays .sort (strings );
163+ final StringBuilder buf = new StringBuilder (sbCapacity );
164+ for (int i = 0 ; i < strings .length ; i ++) {
165+ buf .append (strings [i ]);
166+ }
167+
168+ return new IteratorItem (nodeProxy , buf .toString ());
169+ }
170+
142171 public void addAll (final NodeList other ) {
143- if (!(other instanceof NodeSet )) {
172+ if (!(other instanceof NodeSet )) {
144173 throw new RuntimeException ("not implemented!" );
145174 }
146175 addAll ((NodeSet ) other );
147176 }
148177
149178 @ Override
150179 public boolean contains (final NodeProxy proxy ) {
151- for (final Iterator < IteratorItem > i = list . iterator (); i . hasNext (); ) {
152- final NodeProxy p = ( i . next ()) .proxy ;
153- if (p .compareTo (proxy ) == 0 ) {
180+ for (final IteratorItem iteratorItem : list ) {
181+ final NodeProxy p = iteratorItem .proxy ;
182+ if (p .compareTo (proxy ) == 0 ) {
154183 return true ;
155184 }
156185 }
@@ -159,8 +188,8 @@ public boolean contains(final NodeProxy proxy) {
159188
160189 @ Override
161190 public boolean containsReference (final Item item ) {
162- for (final Iterator < IteratorItem > i = list . iterator (); i . hasNext (); ) {
163- final NodeProxy p = ( i . next ()) .proxy ;
191+ for (final IteratorItem iteratorItem : list ) {
192+ final NodeProxy p = iteratorItem .proxy ;
164193 if (p == item ) {
165194 return true ;
166195 }
@@ -170,8 +199,8 @@ public boolean containsReference(final Item item) {
170199
171200 @ Override
172201 public boolean contains (final Item item ) {
173- for (final Iterator < IteratorItem > i = list . iterator (); i . hasNext (); ) {
174- final NodeProxy p = ( i . next ()) .proxy ;
202+ for (final IteratorItem iteratorItem : list ) {
203+ final NodeProxy p = iteratorItem .proxy ;
175204 if (p .equals (item )) {
176205 return true ;
177206 }
@@ -181,15 +210,15 @@ public boolean contains(final Item item) {
181210
182211 @ Override
183212 public NodeProxy get (final int pos ) {
184- final IteratorItem item = ( IteratorItem ) list .get (pos );
213+ final IteratorItem item = list .get (pos );
185214 return item == null ? null : item .proxy ;
186215 }
187216
188217 public NodeProxy get (final DocumentImpl doc , final NodeId nodeId ) {
189218 final NodeProxy proxy = new NodeProxy (null , doc , nodeId );
190- for (final Iterator < IteratorItem > i = list . iterator (); i . hasNext (); ) {
191- final NodeProxy p = ( i . next ()) .proxy ;
192- if (p .compareTo (proxy ) == 0 ) {
219+ for (final IteratorItem iteratorItem : list ) {
220+ final NodeProxy p = iteratorItem .proxy ;
221+ if (p .compareTo (proxy ) == 0 ) {
193222 return p ;
194223 }
195224 }
@@ -198,9 +227,9 @@ public NodeProxy get(final DocumentImpl doc, final NodeId nodeId) {
198227
199228 @ Override
200229 public NodeProxy get (final NodeProxy proxy ) {
201- for (final Iterator < IteratorItem > i = list . iterator (); i . hasNext (); ) {
202- final NodeProxy p = ( i . next ()) .proxy ;
203- if (p .compareTo (proxy ) == 0 ) {
230+ for (final IteratorItem iteratorItem : list ) {
231+ final NodeProxy p = iteratorItem .proxy ;
232+ if (p .compareTo (proxy ) == 0 ) {
204233 return p ;
205234 }
206235 }
@@ -209,7 +238,7 @@ public NodeProxy get(final NodeProxy proxy) {
209238
210239 @ Override
211240 public int getLength () {
212- return list .size ();
241+ return ( int ) list .size ();
213242 }
214243
215244 @ Override
@@ -219,15 +248,21 @@ public long getItemCountLong() {
219248
220249 @ Override
221250 public Node item (final int pos ) {
222- final NodeProxy p = ((IteratorItem ) list .get (pos )).proxy ;
223- return p == null ? null : p .getNode ();
251+ final IteratorItem iteratorItem = list .get (pos );
252+ if (iteratorItem != null ) {
253+ final NodeProxy p = iteratorItem .proxy ;
254+ if (p != null ) {
255+ return p .getOwnerDocument ().getNode (p );
256+ }
257+ }
258+ return null ;
224259 }
225260
226261 //TODO : evaluate both semantics (item/itemAt)
227262 @ Override
228263 public Item itemAt (final int pos ) {
229- final NodeProxy p = (( IteratorItem ) list .get (pos )). proxy ;
230- return p == null ? null : p ;
264+ final IteratorItem iteratorItem = list .get (pos );
265+ return iteratorItem == null ? null : iteratorItem . proxy ;
231266 }
232267
233268 @ Override
@@ -245,101 +280,89 @@ public SequenceIterator unorderedIterator() {
245280 return new SortedNodeSetIterator (list .iterator ());
246281 }
247282
248- private static final class SortedNodeSetIterator implements NodeSetIterator , SequenceIterator {
249-
283+ private static class SortedNodeSetIterator implements NodeSetIterator , SequenceIterator {
250284 private final Iterator <IteratorItem > ii ;
251285
252286 public SortedNodeSetIterator (final Iterator <IteratorItem > i ) {
253287 ii = i ;
254288 }
255289
256- public final boolean hasNext () {
290+ public boolean hasNext () {
257291 return ii .hasNext ();
258292 }
259293
260294 @ Override
261- public final NodeProxy next () {
262- if (!ii .hasNext ()) {
295+ public NodeProxy next () {
296+ if (!ii .hasNext ()) {
263297 throw new NoSuchElementException ();
264298 } else {
265299 return ii .next ().proxy ;
266300 }
267301 }
268302
269303 @ Override
270- public final void remove () {
304+ public void remove () {
271305 throw new UnsupportedOperationException ();
272306 }
273307
274308 @ Override
275- public final NodeProxy peekNode () {
309+ public NodeProxy peekNode () {
276310 return null ;
277311 }
278312
279313 @ Override
280- public final Item nextItem () {
281- if (!ii .hasNext ()) {
314+ public Item nextItem () {
315+ if (!ii .hasNext ()) {
282316 return null ;
283317 } else {
284318 return ii .next ().proxy ;
285319 }
286320 }
287321
288322 @ Override
289- public final void setPosition (final NodeProxy proxy ) {
323+ public void setPosition (final NodeProxy proxy ) {
290324 throw new UnsupportedOperationException ("NodeSetIterator.setPosition() is not supported by SortedNodeSetIterator" );
291325 }
292326 }
293327
294- private static final class IteratorItem extends OrderedLinkedList . Node {
328+ private static class IteratorItem implements Comparable < IteratorItem > {
295329 private final NodeProxy proxy ;
296- private String value = null ;
330+ private @ Nullable final String value ;
297331
298- public IteratorItem (final NodeProxy proxy , final PathExpr expr ) {
332+ public IteratorItem (final NodeProxy proxy , final String value ) {
299333 this .proxy = proxy ;
300- try {
301- final Sequence seq = expr .eval (proxy , null );
302- final StringBuilder buf = new StringBuilder ();
303- final OrderedLinkedList strings = new OrderedLinkedList ();
304- Item item ;
305- for (final SequenceIterator i = seq .iterate (); i .hasNext (); ) {
306- item = i .nextItem ();
307- strings .add (new OrderedLinkedList .SimpleNode (item .getStringValue ().toUpperCase ()));
308- }
309- for (final Iterator <OrderedLinkedList .SimpleNode > j = strings .iterator (); j .hasNext (); ) {
310- buf .append ((j .next ()).getData ());
311- }
312- value = buf .toString ();
313- } catch (final XPathException e ) {
314- LOG .warn (e .getMessage (), e ); //TODO : throw exception ! -pb
315- } finally {
316- expr .getContext ().runCleanupTasks ();
317- expr .getContext ().reset ();
318- }
334+ this .value = value ;
319335 }
320336
321337 @ Override
322- public int compareTo (final OrderedLinkedList .Node other ) {
323- final IteratorItem o = (IteratorItem ) other ;
324- if (value == null ) {
325- return o .value == null ? Constants .EQUAL : Constants .SUPERIOR ;
326- } else if (o .value == null ) {
338+ public int compareTo (final IteratorItem other ) {
339+ if (value == null ) {
340+ return other .value == null ? Constants .EQUAL : Constants .SUPERIOR ;
341+ } else if (other .value == null ) {
327342 return Constants .INFERIOR ;
328343 } else {
329- return value .compareTo (o .value );
344+ return value .compareTo (other .value );
330345 }
331346 }
332347
333348 @ Override
334- public boolean equals (final OrderedLinkedList .Node other ) {
335- final IteratorItem o = (IteratorItem ) other ;
336- return value .equals (o .value );
349+ public boolean equals (final Object other ) {
350+ if (!(other instanceof IteratorItem )) {
351+ return false ;
352+ }
353+
354+ final IteratorItem otherIteratorItem = (IteratorItem ) other ;
355+ return Objects .equals (value , otherIteratorItem .value );
356+ }
357+
358+ @ Override
359+ public int hashCode () {
360+ return Objects .hashCode (value );
337361 }
338362 }
339363
340364 @ Override
341365 public void add (final NodeProxy proxy ) {
342366 LOG .info ("Called SortedNodeSet.add()" );
343367 }
344-
345368}
0 commit comments