EMMA Coverage Report (generated Sun May 02 20:42:29 CEST 2010)
[all classes][hu.netmind.beankeeper.query.impl]

COVERAGE SUMMARY FOR SOURCE FILE [LazyListImpl.java]

nameclass, %method, %block, %line, %
LazyListImpl.java100% (2/2)76%  (26/34)81%  (1419/1747)89%  (279.6/315)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class LazyListImpl$LazyListIterator100% (1/1)30%  (3/10)62%  (80/130)65%  (18.9/29)
add (Object): void 0%   (0/1)0%   (0/5)0%   (0/1)
hasPrevious (): boolean 0%   (0/1)0%   (0/7)0%   (0/1)
nextIndex (): int 0%   (0/1)0%   (0/3)0%   (0/1)
previous (): Object 0%   (0/1)0%   (0/19)0%   (0/4)
previousIndex (): int 0%   (0/1)0%   (0/5)0%   (0/1)
remove (): void 0%   (0/1)0%   (0/5)0%   (0/1)
set (Object): void 0%   (0/1)0%   (0/5)0%   (0/1)
LazyListImpl$LazyListIterator (LazyListImpl): void 100% (1/1)98%  (43/44)99%  (11.9/12)
hasNext (): boolean 100% (1/1)100% (3/3)100% (1/1)
next (): Object 100% (1/1)100% (34/34)100% (6/6)
     
class LazyListImpl100% (1/1)96%  (23/24)83%  (1339/1617)91%  (260.7/286)
getHooks (): LazyListHooks 0%   (0/1)0%   (0/3)0%   (0/1)
writeReplace (): Object 100% (1/1)45%  (13/29)80%  (4/5)
updateList (int): void 100% (1/1)72%  (438/605)86%  (80.8/94)
optimizeStatements (): void 100% (1/1)79%  (137/174)89%  (32/36)
getStmtOffset (int): long 100% (1/1)86%  (105/122)87%  (13/15)
fixBoundingTerms (Expression, TableTerm, boolean): void 100% (1/1)91%  (259/285)94%  (34.8/37)
optimizeLocalStatement (QueryStatement, Limits): QueryStatement 100% (1/1)91%  (122/134)93%  (25/27)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
LazyListImpl (QueryService, ClassTracker, ConfigurationTracker, SchemaManager... 100% (1/1)100% (74/74)100% (26/26)
access$000 (LazyListImpl): List 100% (1/1)100% (3/3)100% (1/1)
access$100 (LazyListImpl): int 100% (1/1)100% (3/3)100% (1/1)
access$200 (LazyListImpl): boolean 100% (1/1)100% (3/3)100% (1/1)
configurationReload (): void 100% (1/1)100% (33/33)100% (5/5)
get (int): Object 100% (1/1)100% (13/13)100% (3/3)
getStmts (): QueryStatementList 100% (1/1)100% (3/3)100% (1/1)
getUsedTables (SearchResult): Set 100% (1/1)100% (62/62)100% (13/13)
initialize (): void 100% (1/1)100% (15/15)100% (6/6)
isIterationCheap (): boolean 100% (1/1)100% (9/9)100% (1/1)
iterator (): Iterator 100% (1/1)100% (3/3)100% (1/1)
listIterator (): ListIterator 100% (1/1)100% (5/5)100% (1/1)
refresh (): void 100% (1/1)100% (19/19)100% (7/7)
setHooks (LazyListHooks): void 100% (1/1)100% (4/4)100% (2/2)
size (): int 100% (1/1)100% (9/9)100% (2/2)
toString (): String 100% (1/1)100% (3/3)100% (1/1)

1/**
2 * Copyright (C) 2006 NetMind Consulting Bt.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 3 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17 */
18 
19package hu.netmind.beankeeper.query.impl;
20 
21import hu.netmind.beankeeper.parser.*;
22import hu.netmind.beankeeper.query.LazyList;
23import hu.netmind.beankeeper.query.LazyListHooks;
24import hu.netmind.beankeeper.query.QueryService;
25import hu.netmind.beankeeper.model.*;
26import hu.netmind.beankeeper.config.ConfigurationTracker;
27import hu.netmind.beankeeper.schema.SchemaManager;
28import java.util.*;
29import java.io.Serializable;
30import java.io.ObjectStreamException;
31import org.apache.log4j.Logger;
32import org.apache.commons.configuration.event.ConfigurationEvent;
33import hu.netmind.beankeeper.db.Limits;
34import hu.netmind.beankeeper.db.SearchResult;
35 
36/**
37 * This list is a lazy-loading list. It receives a query statement, and
38 * if an item is queried, the list runs the approriate search statement
39 * and loads the referred item (and a given neighbourhood).
40 * @author Brautigam Robert
41 * @version Revision: $Revision$
42 */
43public class LazyListImpl extends AbstractList implements LazyList, Serializable
44{
45   private static Logger logger = Logger.getLogger(LazyListImpl.class);
46   public int BATCH_SIZE = 30;
47   public int BATCH_SIZE_LINEARMULTIPLIER = 3;
48   public int BATCH_SIZE_MAX = 2500;
49   public int MAX_JOINS = 16;
50   
51   private Map unmarshalledObjects = null;
52   private LazyListHooks hooks = null;
53   private QueryStatementList stmts = null;
54 
55   private List list;
56   private boolean hasNext = false;
57   private long[] stmtOffsets;
58   private int offset = 0;
59   private boolean initialized;
60   private int linearCount = 0;
61   private int linearLastIndex = -1;
62 
63   private QueryService queryService = null;
64   private ClassTracker classTracker = null;
65   private ConfigurationTracker config = null;
66   private SchemaManager schemaManager = null;
67 
68   LazyListImpl(QueryService queryService, ClassTracker classTracker, ConfigurationTracker config,
69         SchemaManager schemaManager, QueryStatementList stmts,Map unmarshalledObjects)
70   {
71      this.queryService=queryService;
72      this.classTracker=classTracker;
73      this.schemaManager=schemaManager;
74      this.config=config;
75      this.stmts=stmts;
76      this.unmarshalledObjects=unmarshalledObjects;
77      this.initialized=false;
78      list = null;
79      // Load config
80      configurationReload();
81   }
82 
83   public QueryStatementList getStmts()
84   {
85      return stmts;
86   }
87 
88   /**
89    * If this object is serialized then write a normal array list
90    * instead of this one.
91    */
92   private Object writeReplace()
93      throws ObjectStreamException
94   {
95      logger.debug("assembling serialized version of lazy list...");
96      ArrayList serialized = new ArrayList(this);
97      if ( logger.isDebugEnabled() )
98         logger.debug("writing serialized form with size: "+serialized.size()+", this size: "+size());
99      return serialized;
100   }
101 
102   /**
103    * Get the object on the given.
104    */
105   public Object get(int index)
106   {
107      initialize();
108      updateList(index);
109      return list.get(index-offset);
110   }
111 
112   /**
113    * Calculate the offset of a given statement.
114    */
115   public long getStmtOffset(int index)
116   {
117      // Initialize
118      if ( stmtOffsets == null )
119      {
120         stmtOffsets = new long[stmts.size()+1];
121         stmtOffsets[0]=0;
122         for ( int i=0; i<stmts.size(); i++ )
123            stmtOffsets[i+1]=-1;
124      }
125      // Calculate
126      if ( logger.isDebugEnabled() )
127         logger.debug("calculating size for stmt index: "+index+"/"+stmts.size());
128      if ( stmtOffsets[index] < 0 )
129      {
130         for ( int i=0; i<index; i++ )
131         {
132            if ( stmtOffsets[i+1] >= 0 )
133               continue;
134            SearchResult result = queryService.find( (QueryStatement) stmts.get(i),
135                  new Limits(0,0,-1),null);
136            stmtOffsets[i+1]=stmtOffsets[i]+result.getResultSize();
137         }
138      }
139      // Return
140      logger.debug("returning size: "+stmtOffsets[index]);
141      return stmtOffsets[index];
142   }
143 
144   /**
145    * Get the predicted size from database. This value <strong>never</strong>
146    * changes.
147    */
148   public int size()
149   {
150      initialize();
151      return (int) getStmtOffset(stmts.size());
152   }
153 
154   public void refresh()
155   {
156      list = null;
157      stmtOffsets=null;
158      offset = 0;
159      linearLastIndex = -1;
160      linearCount = 0;
161      hasNext = false;
162   }
163 
164   /**
165    * Try to load the entries around the given index.
166    */
167   private void updateList(int index)
168   {
169      // Initialize lazy list
170      initialize();
171      // Keep track of linear iterations
172      if ( index == linearLastIndex+1 )
173         linearCount++;
174      else
175         linearCount=0;
176      linearLastIndex=index;
177      // Check bounds
178      if ( index < 0 )
179         throw new ArrayIndexOutOfBoundsException("lazy list index given was: "+index+", thats < 0 and illegal.");
180      if ( (list!=null) && (index<offset+list.size()) && (index>=offset) )
181         return; // List has the desired item
182      // Determine whether the update will get the next page linearly
183      boolean nextPage = false;
184      if ( list != null )
185         nextPage = ( index == offset+list.size() );
186      // Determine the startindex and size of the current select
187      int batchSize = BATCH_SIZE;
188      if ( list != null )
189         batchSize = list.size();
190      if ( linearCount >= batchSize )
191         batchSize = batchSize * BATCH_SIZE_LINEARMULTIPLIER;
192      else
193         batchSize = BATCH_SIZE;
194      if ( batchSize > BATCH_SIZE_MAX )
195         batchSize = BATCH_SIZE_MAX;
196      int startIndex = 0;
197      if ( index < offset )
198         startIndex = (index/batchSize)*batchSize;
199      else
200         startIndex = index;
201      if ( startIndex < 0 )
202         startIndex = 0;
203      if ( logger.isDebugEnabled() )
204         logger.debug("list index: "+index+", startindex: "+startIndex+", batchsize: "+batchSize+", linearcount was: "+linearCount);
205      linearCount = 0;
206      linearLastIndex = index;
207      // Determine the statement to use for given index
208      HashMap session = new HashMap();
209      getStmtOffset(0); // Initialize offsets
210      int stmtIndex = 0;
211      long realOffset = 0;
212      if ( hooks!=null )
213         stmtIndex = hooks.preIndexing(session,startIndex);
214      if ( stmtIndex < 0 )
215      {
216         stmtIndex = 0;
217         while ( (stmtIndex<stmts.size()) && (stmtOffsets[stmtIndex]>=0) &&
218               (stmtOffsets[stmtIndex+1]>=0) && (stmtOffsets[stmtIndex+1]<=startIndex) )
219         {
220            realOffset=stmtOffsets[stmtIndex];
221            stmtIndex++;
222         }
223      }
224      if ( stmtIndex >= stmts.size() )
225         throw new ArrayIndexOutOfBoundsException("Tried to reach index: "+index+", but that was not available.");
226      if ( logger.isDebugEnabled() )
227         logger.debug("asked index is: "+index+", real offset: "+realOffset+", stmt index: "+stmtIndex+", start index: "+startIndex);
228      // Now load the result set, which is possibly distributed in multiple
229      // queries.
230      offset = startIndex;
231      List previousList = new ArrayList();
232      if ( nextPage )
233         previousList = new ArrayList(list);
234      list = new ArrayList(batchSize);
235      // Load the already unmarshalled objects. Load until
236      // list vector is full, or out of result entries. Note: we load
237      // plus one entry, so we know, that there is a next entry.
238      boolean override = false;
239      while ( (stmtIndex<stmts.size()) && ((list.size()<=batchSize)||(override)) )
240      {
241         if ( logger.isDebugEnabled() )
242            logger.debug("lazy list statement iteration: "+stmtIndex+"/"+stmts.size()+
243                  ", current size: "+list.size()+"/"+batchSize);
244         override=false;
245         // Get the query, and optimize it
246         QueryStatement stmt = (QueryStatement) stmts.get(stmtIndex);
247         Limits limits = new Limits((int) (startIndex-stmtOffsets[stmtIndex]),batchSize+1-list.size(),0);
248         if ( limits.getOffset() < 0 )
249            limits.setOffset(0);
250         // Compute the total join count of the selected term
251         int totalJoinCount = 0;
252         SpecifiedTableTerm mainTerm = stmt.getSpecifiedTerm(
253               (TableTerm) stmt.getSelectTerms().get(0));
254         if ( mainTerm.getRelatedLeftTerms().size() > MAX_JOINS )
255         {
256            // Modify limits, so it does not select more rows than left
257            // table terms. This ensures, that the select will not contain
258            // more left table terms.
259            if ( limits.getLimit() > MAX_JOINS )
260            {
261               limits.setLimit(MAX_JOINS+1);
262               batchSize = list.size() + MAX_JOINS;
263               logger.debug("adjusting limits, so max joins can be suited, new batch size: "+batchSize+", list size is: "+list.size());
264            }
265            // If there are many left table terms, then optimize this select
266            // locally. This means, eliminate all left table terms, which will
267            // not be used.
268            stmt = optimizeLocalStatement(stmt,limits);
269         }
270         // Make query
271         if ( hooks != null )
272            stmt = hooks.preSelect(session,stmt,previousList,limits,new Limits(offset,batchSize+1,0));
273         SearchResult result = queryService.find(stmt,limits,unmarshalledObjects);
274         // Set for next iteration
275         startIndex+=result.getResult().size();
276         list.addAll(result.getResult());
277         if ( hooks != null )
278            override = hooks.postSelect(session,list,new Limits(offset,batchSize+1,0));
279         // Postoperation adjustments
280         if ( list.size() > batchSize )
281         {
282            logger.debug("list size "+list.size()+" is greater than batchsize "+batchSize+", iteration complete");
283            // This means, that the list contained enough items for
284            // the query, which means return only the exact results.
285            // The size can not be determined now.
286            list = list.subList(0,batchSize);
287            hasNext = true;
288            // List is ok for now, we don't need more
289            if ( logger.isDebugEnabled() )
290               logger.debug("updated list with full window, size is: "+list.size()+", index was: "+index);
291            return;
292         } else {
293            hasNext = false;
294            // Compute statement length if the length is not yet known
295            if ( stmtOffsets[stmtIndex+1] < 0 )
296            {
297               if ( list.size() == 0 )
298               {
299                  logger.debug("list size was 0 for this iteration");
300                  // There is no result. This can be caused by two things:
301                  // - This statement is really 0 length
302                  // - Statement interval ends before this start index is reached,
303                  // but may contain items.
304                  // Let's just calculate the sizes up until now
305                  getStmtOffset(stmtIndex+1);
306               } else if ( list.size() <= batchSize ) {
307                  logger.debug("list size "+list.size()+" is not greater than batchsize "+batchSize);
308                  // This means, that the list does not contain enough items,
309                  // so the size can be exactly determined.
310                  stmtOffsets[stmtIndex+1]=startIndex;
311               }
312            }
313         }
314         // Decrease cycle invariant function (in english: increase index)
315         stmtIndex++;
316      }
317      if ( logger.isDebugEnabled() )
318         logger.debug("updated list, size is: "+list.size()+", index was: "+index);
319   }
320 
321   private void initialize()
322   {
323      if ( initialized )
324         return;
325      initialized=true;
326      // If not yet queried, and the number of statements is big,
327      // then do a pre-select, to determine which statements will be
328      // used anyway, and drop those statements, which will have no
329      // results.
330      if ( stmts.size()>2 )
331         optimizeStatements();
332   }
333 
334   private Set getUsedTables(SearchResult result)
335   {
336      HashSet usedTableNames = new HashSet();
337      for ( int i=0; i<result.getResult().size(); i++ )
338      {
339         Integer classId = new Integer(((Map)result.getResult().get(i)).get("classid").toString());
340         ClassEntry entry = classTracker.getClassEntry(classId);
341         ClassInfo info = classTracker.getClassInfo(entry);
342         while ( (entry!=null) && (info.isStorable()) )
343         {
344            // Insert it's table name into the set
345            String usedTableName = schemaManager.getTableName(entry);
346            usedTableNames.add(usedTableName);
347            // Goto super
348            entry = entry.getSuperEntry();
349            if ( entry != null )
350               info = classTracker.getClassInfo(entry);
351         }
352      }
353      return usedTableNames;
354   }
355 
356   /**
357    * The task of this method is to temporary remove those joined left table terms,
358    * which will not be used in this page of the resultset.
359    */
360   private QueryStatement optimizeLocalStatement(QueryStatement stmt,Limits limits)
361   {
362      logger.debug("executing local optimization");
363      if ( stmt.getMode() != QueryStatement.MODE_FIND )
364         return stmt;
365      // First, copy the statement, so it won't affect later use
366      QueryStatement copyStmt = stmt.deepCopy();
367      // Then modify the statement to select only the tables the statement
368      // reaches with the given limits. (So remove all left terms for now)
369      copyStmt.setMode(QueryStatement.MODE_VIEW);
370      TableTerm selectTerm = (TableTerm) copyStmt.getSelectTerms().get(0);
371      SpecifiedTableTerm specifiedSelectTerm = (SpecifiedTableTerm) copyStmt.getSpecifiedTerm(selectTerm);
372      logger.debug("local optimization detects "+specifiedSelectTerm.getRelatedLeftTerms().size()+" left table terms.");
373      specifiedSelectTerm.getRelatedLeftTerms().clear();
374      copyStmt.getSelectTerms().set(0,new ReferenceTerm(selectTerm,
375               "persistence_id","classid",new MathematicalPostfixFunction(">>","45")));
376      copyStmt.setStaticRepresentation(copyStmt.getStaticRepresentation()+"LazyModifiedForTableSet");
377      copyStmt.getOrderByList().clear();
378      // Execute query
379      SearchResult result = queryService.find(copyStmt,limits,null);
380      // Get all the tables this query will reach
381      Set usedTableNames = getUsedTables(result);
382      if ( logger.isDebugEnabled() )
383         logger.debug("determined, that used tables of given page are: "+usedTableNames);
384      // Remove all left table terms from the original statement which are
385      // not used.
386      copyStmt = stmt.deepCopy();
387      selectTerm = (TableTerm) copyStmt.getSelectTerms().get(0);
388      specifiedSelectTerm = (SpecifiedTableTerm) copyStmt.getSpecifiedTerm(selectTerm);
389      Iterator leftTermIterator = specifiedSelectTerm.getRelatedLeftTerms().iterator();
390      while ( leftTermIterator.hasNext() )
391      {
392         SpecifiedTableTerm.LeftjoinEntry entry = (SpecifiedTableTerm.LeftjoinEntry) leftTermIterator.next();
393         if ( ! usedTableNames.contains(entry.term.getTableName()) )
394            leftTermIterator.remove();
395      }
396      copyStmt.setStaticRepresentation(null);
397      return copyStmt;
398   }
399 
400   /**
401    * The task of this method is to permanently remove those statements from the
402    * list which will yield an empty resultset on execution. Because removing
403    * these statments from the set of statements this list contains will not
404    * alter the result set itself, the statement can be removed.
405    */
406   private void optimizeStatements()
407   {
408      logger.debug("executing optimizing statement");
409      // To do this, we do the following:
410      // - Get the root statmenet from which all statements come, but which
411      //   is based on a possibly non-storable class
412      // - Change the main term to classes table, to select class ids
413      // - Run the altered query which will not result in objects, but in
414      //   classes that would be returned by the original.
415      QueryStatement classIdsStmt = stmts.getRoot();
416      if ( classIdsStmt.getMode()!=QueryStatement.MODE_FIND )
417         return;
418      TableTerm selectTerm = (TableTerm) classIdsStmt.getSelectTerms().get(0);
419      SpecifiedTableTerm newTerm = new SpecifiedTableTerm("persistence_classes",selectTerm.getAlias());
420      classIdsStmt.replace(selectTerm,newTerm,"id");
421      classIdsStmt.setSelectTerms(new ArrayList());
422      classIdsStmt.getSelectTerms().add(new ReferenceTerm(newTerm,"id","classid"));
423      classIdsStmt.setOrderByList(null);
424      classIdsStmt.setMode(QueryStatement.MODE_VIEW);
425      classIdsStmt.setStaticRepresentation(classIdsStmt.getStaticRepresentation()+"LazyModifiedForTableSet");
426      // Now, the statement is almost ready, but now we need to walk the
427      // expression tree, and determine which conditions bound the classes
428      fixBoundingTerms(classIdsStmt.getQueryExpression(),newTerm,true);
429      // Execute statement
430      SearchResult result = queryService.find(classIdsStmt, null,null);
431      // Now assemble each and every table name that will be used by the
432      // main selects. These are not only those returned by previous select,
433      // but all 'supertables' of them also.
434      Set usedTableNames = getUsedTables(result);
435      if ( logger.isDebugEnabled() )
436         logger.debug("determined, that used tables are: "+usedTableNames);
437      // Now go through all statements, and determine whether they will be
438      // used or not. If a statement has a main select term which is not
439      // used, then delete the whole statement. Check the left terms too,
440      // and remove all non-used left terms.
441      Iterator stmtIterator = stmts.iterator();
442      while ( stmtIterator.hasNext() )
443      {
444         QueryStatement stmt = (QueryStatement) stmtIterator.next();
445         // Check main term
446         TableTerm mainTerm = (TableTerm) stmt.getSelectTerms().get(0);
447         SpecifiedTableTerm specifiedMainTerm = (SpecifiedTableTerm) stmt.getSpecifiedTerm(mainTerm);
448         if ( ! usedTableNames.contains(mainTerm.getTableName()) )
449         {
450            // Main term is not used, so remove
451            stmtIterator.remove();
452            if ( logger.isDebugEnabled() )
453               logger.debug("removing statement with main term: "+mainTerm);
454         } else {
455            // Main term is used, but check it's left terms
456            Iterator leftTermIterator = specifiedMainTerm.getRelatedLeftTerms().iterator();
457            while ( leftTermIterator.hasNext() )
458            {
459               SpecifiedTableTerm.LeftjoinEntry joinEntry = (SpecifiedTableTerm.LeftjoinEntry) leftTermIterator.next();
460               if ( ! usedTableNames.contains(joinEntry.term.getTableName()) )
461               {
462                  // Left term will not be used ever, so remove it, but
463                  // don't forget the expressions for this left term.
464                  leftTermIterator.remove();
465                  if ( logger.isDebugEnabled() )
466                     logger.debug("removing left table '"+joinEntry.term+"' from statement with main term: "+mainTerm);
467               }
468            }
469         }
470      }
471   }
472 
473   /**
474    * Search for operators which are around the given term, and change
475    * the term with which it is in relation to classid, if it's a bounding
476    * relation.
477    */
478   private void fixBoundingTerms(Expression expr, TableTerm mainTerm, boolean positive)
479   {
480      boolean localPositive = true;
481      for ( int i=0; i<expr.size(); i++ )
482      {
483         Object atom = expr.get(i);
484         if ( atom instanceof String )
485         {
486            if ( ("or".equalsIgnoreCase((String) atom)) ||
487                 ("and".equalsIgnoreCase((String) atom)) )
488               localPositive = true;
489            if ( "not".equalsIgnoreCase((String) atom) )
490               localPositive = false;
491         } else if ( atom instanceof Expression ) {
492            fixBoundingTerms((Expression) atom, mainTerm, !(positive ^ localPositive));
493         } else if ( atom instanceof TableTerm ) {
494            if ( mainTerm.equals(atom) )
495            {
496               // Found the term, now if it's bounded, then change
497               // the other term
498               int direction = 0;
499               if ( (i+1<expr.size()) && (
500                        ("!=".equals(expr.get(i+1))) || ("<>".equals(expr.get(i+1))) ||
501                        ("=".equals(expr.get(i+1)))  || ("in".equals(expr.get(i+1)))  ) )
502                  direction = 1;
503               if ( (i-1>=0) && (
504                        ("!=".equals(expr.get(i-1))) || ("<>".equals(expr.get(i-1))) ||
505                        ("=".equals(expr.get(i-1)))  || ("in".equals(expr.get(i-1))) ) )
506                  direction = -1;
507               if ( direction == 0 )
508                  continue; // Potential bounding operator not found
509               // Determine whether it's really bound
510               if (!( (!((positive) ^ (localPositive))) ^ 
511                    (("=".equals(expr.get(i+direction))) || ("in".equals(expr.get(i+direction))) ) ))
512               {
513                  Object term = expr.get(i+2*direction);
514                  logger.debug("found bounding term: "+term);
515                  if ( term instanceof ReferenceTerm )
516                  {
517                     // It's bound to another referenceterm or constantterm
518                     ReferenceTerm newTerm = new ReferenceTerm((ReferenceTerm) term);
519                     newTerm.setFunction(new MathematicalPostfixFunction(">>","45"));
520                     expr.set(i+2*direction,newTerm);
521                  } else if ( term instanceof ConstantTerm ) {
522                     // Bound to constant term, so convert to classid
523                     Object value = ((ConstantTerm)term).getValue();
524                     if ( value instanceof Long )
525                     {
526                        expr.set(i+2*direction,new ConstantTerm(
527                                 new Long(((Long)value).longValue()>>45)));
528                     } else if ( value instanceof Collection ) {
529                        ArrayList newValue = new ArrayList();
530                        Iterator oldIterator = ((Collection)value).iterator();
531                        while ( oldIterator.hasNext() )
532                           newValue.add(new Long(((Long)oldIterator.next()).longValue()>>45));
533                        expr.set(i+2*direction,new ConstantTerm(newValue));
534                     }
535                  }
536               }
537            }
538         }
539      }
540   }
541 
542   public Iterator iterator()
543   {
544      return listIterator();
545   }
546 
547   public ListIterator listIterator()
548   {
549      return new LazyListIterator();
550   }
551   
552   public String toString()
553   {
554      return super.toString();
555   }
556 
557   /**
558    * This is not an optimal implementation, it only checks whether the list 
559    * is smaller than the smallest window.
560    */
561   public boolean isIterationCheap()
562   {
563      return size() < BATCH_SIZE;
564   }
565 
566   /**
567    * This internal iterator avoids using size() method for
568    * optimized iteration.
569    */
570   public class LazyListIterator implements ListIterator
571   {
572      public int currentIndex = 0;
573      public boolean currentHasNext = false;
574 
575      public LazyListIterator()
576      {
577         // Pre-read if there is a first item
578         currentIndex=0;
579         if ( list == null )
580         {
581            try
582            {
583               get(currentIndex);
584               currentHasNext = true;
585            } catch ( IndexOutOfBoundsException e ) {
586               currentHasNext = false;
587            }
588         } else {
589            currentHasNext = offset+list.size() > 0;
590         }
591      }
592      
593      public void add(Object o)
594      {
595         throw new UnsupportedOperationException("LazyList does not support addition.");
596      }
597 
598      public boolean hasNext()
599      {
600         return currentHasNext;
601      }
602 
603      public boolean hasPrevious()
604      {
605         return currentIndex > 0; // All items have previous except first
606      }
607 
608      public Object next()
609      {
610         Object result = get(currentIndex);
611         currentIndex++;
612         if ( currentIndex < offset+list.size() )
613            currentHasNext=true;
614         else
615            currentHasNext=hasNext;
616         return result;
617      }
618      
619      public int nextIndex()
620      {
621         return currentIndex;
622      }
623 
624      public Object previous()
625      {
626         Object result = get(currentIndex-1);
627         currentIndex--;
628         currentHasNext=true;
629         return result;
630      }
631 
632      public int previousIndex()
633      {
634         return currentIndex-1;
635      }
636 
637      public void remove()
638      {
639         throw new UnsupportedOperationException("LazyList does not support remove.");
640      }
641 
642      public void set(Object o)
643      {
644         throw new UnsupportedOperationException("LazyList does not support set.");
645      }
646   }
647 
648   public LazyListHooks getHooks()
649   {
650      return hooks;
651   }
652   public void setHooks(LazyListHooks hooks)
653   {
654      this.hooks=hooks;
655   }
656 
657   public void configurationReload()
658   {
659      BATCH_SIZE = config.getConfiguration().
660         getInt("beankeeper.list.batch_size",30);
661      BATCH_SIZE_MAX = config.getConfiguration().
662         getInt("beankeeper.list.batch_size_max",2500);
663      BATCH_SIZE_LINEARMULTIPLIER = config.getConfiguration().
664         getInt("beankeeper.list.batch_size_linearmultiplier",3);
665      MAX_JOINS = config.getConfiguration().
666         getInt("beankeeper.list.max_joins",16);
667   }
668}
669 
670 
671 

[all classes][hu.netmind.beankeeper.query.impl]
EMMA 2.0.5312debian (C) Vladimir Roubtsov