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

COVERAGE SUMMARY FOR SOURCE FILE [QueryServiceImpl.java]

nameclass, %method, %block, %line, %
QueryServiceImpl.java100% (3/3)87%  (13/15)83%  (1220/1475)90%  (241.6/269)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class QueryServiceImpl100% (1/1)85%  (11/13)82%  (1185/1437)90%  (236.7/264)
find (String): LazyList 0%   (0/1)0%   (0/7)0%   (0/1)
findSingle (String): Object 0%   (0/1)0%   (0/5)0%   (0/1)
unmarshallObject (ClassInfo, Map, Map, Map, QueryStatement): Object 100% (1/1)77%  (195/252)88%  (42/48)
find (QueryStatement, Limits, Map): SearchResult 100% (1/1)80%  (398/500)86%  (80.8/94)
find (String, Object [], TimeControl, Map): LazyList 100% (1/1)82%  (353/429)92%  (59.9/65)
find (QueryStatement, Limits): SearchResult 100% (1/1)93%  (69/74)91%  (10/11)
<static initializer> 100% (1/1)100% (7/7)100% (2/2)
QueryServiceImpl (): void 100% (1/1)100% (48/48)100% (16/16)
find (String, Object []): LazyList 100% (1/1)100% (7/7)100% (1/1)
findSingle (String, Object []): Object 100% (1/1)100% (14/14)100% (4/4)
handle (PersistenceEvent): void 100% (1/1)100% (69/69)100% (14/14)
init (Map): void 100% (1/1)100% (16/16)100% (4/4)
release (): void 100% (1/1)100% (9/9)100% (3/3)
     
class QueryServiceImpl$1100% (1/1)100% (1/1)88%  (23/26)88%  (0.9/1)
<static initializer> 100% (1/1)88%  (23/26)88%  (0.9/1)
     
class QueryServiceImpl$IdsEntry100% (1/1)100% (1/1)100% (12/12)100% (5/5)
QueryServiceImpl$IdsEntry (Map, Set, ClassInfo): void 100% (1/1)100% (12/12)100% (5/5)

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 org.apache.log4j.Logger;
22import java.util.*;
23import hu.netmind.beankeeper.common.StoreException;
24import hu.netmind.beankeeper.query.LazyList;
25import hu.netmind.beankeeper.query.LazyListHooks;
26import hu.netmind.beankeeper.query.QueryService;
27import hu.netmind.beankeeper.serial.SerialTracker;
28import hu.netmind.beankeeper.lock.LockTracker;
29import hu.netmind.beankeeper.config.ConfigurationTracker;
30import hu.netmind.beankeeper.parser.*;
31import hu.netmind.beankeeper.node.*;
32import hu.netmind.beankeeper.model.*;
33import hu.netmind.beankeeper.transaction.Transaction;
34import hu.netmind.beankeeper.transaction.TransactionStatistics;
35import hu.netmind.beankeeper.transaction.TransactionTracker;
36import hu.netmind.beankeeper.db.Limits;
37import hu.netmind.beankeeper.event.EventDispatcher;
38import hu.netmind.beankeeper.event.PersistenceEventListener;
39import hu.netmind.beankeeper.event.PersistenceEvent;
40import hu.netmind.beankeeper.db.SearchResult;
41import hu.netmind.beankeeper.db.Database;
42import hu.netmind.beankeeper.object.PersistenceMetaData;
43import hu.netmind.beankeeper.object.ObjectTracker;
44import hu.netmind.beankeeper.object.Identifier;
45import hu.netmind.beankeeper.serial.Serial;
46import hu.netmind.beankeeper.type.TypeHandler;
47import hu.netmind.beankeeper.type.TypeHandlerTracker;
48import hu.netmind.beankeeper.management.ManagementTracker;
49import hu.netmind.beankeeper.node.NodeManager;
50import hu.netmind.beankeeper.operation.OperationTracker;
51import hu.netmind.beankeeper.cache.ResultsCache;
52import hu.netmind.beankeeper.schema.SchemaManager;
53import hu.netmind.beankeeper.store.event.*;
54import hu.netmind.beankeeper.transaction.event.*;
55import javax.sql.DataSource;
56 
57/**
58 * Implements the query interface to offer query methods based on
59 * programmatic and freetext queries.
60 * @author Brautigam Robert
61 * @version Revision: $Revision$
62 */
63public class QueryServiceImpl implements QueryService, PersistenceEventListener
64{
65   private static Logger logger = Logger.getLogger(QueryServiceImpl.class);
66   private static Logger operationsLogger = Logger.getLogger("hu.netmind.beankeeper.operations");
67 
68   private QueryStatistics queryStatistics = null;
69   private Map<Transaction,Set<String>> transactionTables = Collections.synchronizedMap(new HashMap<Transaction,Set<String>>());
70 
71   private ManagementTracker managementTracker = null; // Injected
72   private TransactionTracker transactionTracker = null; // Injected
73   private ObjectTracker objectTracker = null; // Injected
74   private SerialTracker serialTracker = null; // Injected
75   private Database database = null; // Injected
76   private ClassTracker classTracker = null; // Injected
77   private TypeHandlerTracker typeHandlerTracker = null; // Injected
78   private OperationTracker operationTracker = null; // Injected
79   private ResultsCache cache = null; // Injected
80   private ConfigurationTracker config = null; // Injected
81   private EventDispatcher eventDispatcher = null; // Injected
82   private SchemaManager schemaManager = null; // Injected
83 
84   /**
85    * Construct this store with the given parameters.
86    */
87   public void init(Map parameters)
88   {
89      // Register
90      eventDispatcher.registerListener(this);
91      // Create the operations mbean and register
92      queryStatistics = new QueryStatistics();
93      managementTracker.registerBean("QueryStatistics",queryStatistics);      
94   }
95 
96   /**
97    * Release resources.
98    */
99   public void release()
100   {
101      eventDispatcher.unregisterListener(this);
102      managementTracker.deregisterBean("QueryStatistics");      
103   }
104 
105   /**
106    * Query an object from the datastore.
107    * @param statement The query statement to select.
108    */
109   public LazyList find(String statement)
110   {
111      return find(statement,null,null,null);
112   }
113 
114   /**
115    * Same as <code>find(statement)</code>. When a statement contains
116    * the question mark (?), the object which should be in the place of
117    * the mark should be given as parameters (parameters are usually of
118    * Date, or custom classes).
119    * @param statement The query statement to execute.
120    * @param parameters The parameters.
121    */
122   public LazyList find(String statement, Object[] parameters)
123   {
124      return find(statement,parameters,null,null);
125   }
126 
127   /**
128    * This method in addition to all usual parameters can define the
129    * exact time of the query with the timeControl parameter. If the
130    * query is a historical query, this control will be overridden.
131    * @param statement The query statement to execute.
132    * @param parameters The parameters.
133    * @param timeControl The exact default time of the query.
134    */
135   public LazyList find(String statement, Object[] parameters, TimeControl timeControl, Map unmarshalledObjects)
136   {
137      // {{{ Parse statement, and create result list
138      // Convert object parameters. If they contain
139      // objects, substitute with object id
140      Transaction transaction = transactionTracker.getTransaction(TransactionTracker.TX_REQUIRED);
141      transaction.begin();
142      long startTime = System.currentTimeMillis();
143      try
144      {
145         Object[] realParameters = null;
146         if ( parameters != null )
147         {
148            realParameters = new Object[parameters.length];
149            for ( int i=0; i<parameters.length; i++ )
150            {
151               if ( parameters[i] == null )
152               {
153                  // Handle null parameters
154                  realParameters[i]=null;
155               } else {
156                  // If parameter is not null, translate object parameters
157                  // to persistent id, leave others
158                  ClassTracker.ClassType type = classTracker.getType(parameters[i].getClass());
159                  if ( type == ClassTracker.ClassType.TYPE_RESERVED )
160                     throw new StoreException("parameter at position: "+i+", value: "+parameters[i]+" is of unsupported type.");
161                  if ( (type == ClassTracker.ClassType.TYPE_OBJECT) && 
162                        (!(parameters[i] instanceof Collection)) && 
163                        (!(parameters[i] instanceof Identifier)) && 
164                        (!(parameters[i] instanceof TimeControl)) )
165                  {
166                     // If object has no id, that's not a problem. It will
167                     // receive an id of 0, and no object should match
168                     // that id anyway.
169                     realParameters[i]=new Identifier(objectTracker.getIdentifier(parameters[i]));
170                  } else if ( parameters[i] instanceof Collection ) {
171                     // Check, whether the collection's items are objects,
172                     // in which case translate them to their ids
173                     ArrayList result = new ArrayList();
174                     Iterator itemIterator = ((Collection) parameters[i]).iterator();
175                     while ( itemIterator.hasNext() )
176                     {
177                        Object item = itemIterator.next();
178                        if ( classTracker.getType(item.getClass()) == ClassTracker.ClassType.TYPE_OBJECT )
179                           result.add(objectTracker.getIdentifier(item));
180                        else
181                           result.add(item);
182                     }
183                     realParameters[i]=result;
184                  } else {
185                     realParameters[i]=parameters[i];
186                  }
187               }
188               if ( logger.isDebugEnabled() )
189                  logger.debug("parameter: "+parameters[i]+" -> real parameter #"+i+":"+realParameters[i]);
190            }
191         }
192         // Process it, get expression
193         QueryStatementList stmts = null;
194         try
195         {
196            // Only apply in-transaction search conditions if there is a transaction
197            // and something changed during transaction. Only calculate if
198            // no 'default default' is given.
199            Set modifiedTables = transactionTables.get(transaction);
200            if ( modifiedTables == null )
201               modifiedTables = new HashSet();
202            if ( timeControl == null )
203            {
204               Long serial = serialTracker.getNextSerial();
205               Long txSerial = transaction.getSerial();
206               timeControl = new TimeControl(serial,txSerial,false);
207            }
208            // Parse statement
209            if ( logger.isDebugEnabled() )
210               logger.debug("executing parser, serial: "+timeControl.getSerial()+", tx serial: "+timeControl.getTxSerial());
211            stmts = new QueryParser(statement,realParameters, new WhereResolver(classTracker,typeHandlerTracker,
212                     schemaManager),timeControl,modifiedTables).query();
213            // Wait now for all commits() before the given serial to finish.
214            // If this would not be the case, the lazy list might not
215            // contain the data from previously initiated commits. Which
216            // would mean, once those finished, the lazy list would change.
217            operationTracker.waitForQuery(timeControl.getSerial());
218         } catch ( ParserException e ) {
219            if ( e.getCode() == ParserException.ABORT )
220            {
221               logger.error("aborting query, because of parser exception.");
222               throw new StoreException(e.getMessage(),e);
223            } else {
224               logger.info("returning empty result list because of non-fatal symbol error. Parser said: "+e.getMessage()+", statement was: "+statement);
225               return new EmptyLazyListImpl(); // Return empty list on non-fatal symbol errors
226            }
227         } catch ( StoreException e ) {
228            throw e;
229         } catch ( Exception e ) {
230            throw new StoreException("unknown exception while select",e);
231         }
232         // Return list
233         return new LazyListImpl(this,classTracker,config,schemaManager,stmts,unmarshalledObjects);
234      } catch ( StoreException e ) {
235         transaction.markRollbackOnly();
236         throw e;
237      } catch ( Throwable e ) {
238         transaction.markRollbackOnly();
239         throw new StoreException("unexpected exception",e);
240      } finally {
241         transaction.commit();
242         // Add to statistics
243         long endTime = System.currentTimeMillis();
244         synchronized ( queryStatistics )
245         {
246            queryStatistics.setQueryCount(queryStatistics.getQueryCount()+1);
247            queryStatistics.setQueryTime(queryStatistics.getQueryTime()+(endTime-startTime));
248         }
249      }
250      // }}}
251   }
252 
253   /**
254    * Same as <code>find(statement,parameters)</code>, but the result should be
255    * a single object.
256    * @param statement The query statement to execute.
257    * @param parameters The parameters to the statement.
258    * @return The object selected, or null if no such object exists. If
259    * the result contains more objects, an arbitrary one is selected.
260    */
261   public Object findSingle(String statement, Object[] parameters)
262   {
263      // {{{ Call normal find and evaluate result
264      Iterator iterator = find(statement,parameters).iterator();
265      if ( iterator.hasNext() )
266         return iterator.next();
267      return null;
268      // }}}
269   }
270 
271   /**
272    * Same as <code>find(statement)</code>, but the result should be
273    * a single object.
274    * @param statement The query statement to execute.
275    * @return The object selected, or null if no such object exists. If
276    * the result contains more objects, an arbitrary one is selected.
277    */
278   public Object findSingle(String statement)
279   {
280      return findSingle(statement,null);
281   }
282 
283   /**
284    * Internal raw loading. All finder methods sooner or later call into
285    * this method to get real results in form of attribute name-value maps.
286    */
287   public SearchResult find(QueryStatement stmt, Limits limits)
288   {
289      // {{{ Do physical query
290      Transaction transaction = transactionTracker.getTransaction(
291            TransactionTracker.TX_OPTIONAL);
292      if ( transaction == null )
293         throw new StoreException("there was not transaction in find");
294      // First, check if statement is visible from this transaction
295      TimeControl timeControl = stmt.getTimeControl();
296      if ( (timeControl.isApplyTransaction()) && (timeControl.getTxSerial()!=null) &&
297           (!timeControl.getTxSerial().equals(transaction.getSerial())) &&
298           (transactionTracker.hasTransaction(timeControl.getTxSerial())) )
299         throw new StoreException("tried to do a query which was outside it's transaction '"+
300               timeControl.getTxSerial()+"', which was still open. Current tx was: "+transaction.getSerial());
301      // Get resultset from cache or database
302      SearchResult result = cache.getEntry(stmt,limits);
303      if ( result == null )
304      {
305         result = database.search(transaction,stmt,limits);
306         cache.addEntry(stmt,limits,result);
307      }
308      return result;
309      // }}}
310   }
311  
312   /**
313    * Unmarshall an object. This means create an object of given class
314    * and set attributes from a given map of attributes. All referred
315    * objects are assumed to be in the already allocated list, indexed
316    * by object id.
317    * @param classInfo The class info of the object that needs to be instantiated.
318    * @param marshalledValues The attributes values.
319    * @param unmarshalledObjects The already unmarshalled objects.
320    */
321   private Object unmarshallObject(ClassInfo classInfo, Map marshalledValues, 
322         Map unmarshalledObjects, Map missingAttributes, QueryStatement stmt)
323      throws InstantiationException, IllegalAccessException
324   {
325      // {{{ Umarshall object
326      Object obj = classInfo.newInstance(marshalledValues);
327      if ( obj == null )
328         return null;
329      // Important! Register object into tracker!
330      // Note: all attributes are updated into the object tracker.
331      // Previously this was not done, because object's had a shared
332      // state (instances of the same database row), but now no shared
333      // state exists (at least, not with attributes).
334      objectTracker.registerObject(obj,(Long) marshalledValues.get("persistence_id"),
335            stmt.getTimeControl().getSerial(),
336            ((Long) marshalledValues.get("persistence_start")),
337            ((Long) marshalledValues.get("persistence_end")));
338      objectTracker.updateObject(obj,marshalledValues);
339      unmarshalledObjects.put(marshalledValues.get("persistence_id"),obj);
340      // Set properties in obj, go through object attributes
341      // (except is the object is of primitive type)
342      List attributeNames = classInfo.getAttributeNames();
343      for ( int o=0; (o<attributeNames.size()) && 
344            (!classInfo.isPrimitive()); o++ )
345      {
346         String attributeName = attributeNames.get(o).toString();
347         // Handle peristence_id specially. If this is an attribute
348         // named something like persistenceId, then fill in the id.
349         if ( ("persistence_id".equalsIgnoreCase(attributeName)) || 
350               ("persistenceid".equalsIgnoreCase(attributeName)) )
351         {
352            // Fill attribute with persistence id
353            classInfo.setAttributeValue(obj,attributeName,marshalledValues.get("persistence_id"));
354            continue;
355         }
356         // Handle other (normal) attributes
357         Object attributeValue = marshalledValues.get(attributeName.toLowerCase());
358         if ( logger.isDebugEnabled() )
359            logger.debug("setting object property: "+attributeName+", value: "+attributeValue);
360         Class attributeClass = classInfo.getAttributeType(attributeName);
361         if ( attributeClass == null )
362         {
363            logger.error("object property '"+attributeName+"' cannot set, object has no such property.");
364            continue;
365         }
366         switch ( classTracker.getType(attributeClass) )
367         {
368            case TYPE_PRIMITIVE:
369               classInfo.setAttributeValue(obj,attributeName,attributeValue);
370               break;
371            case TYPE_HANDLED:
372               TypeHandler handler = typeHandlerTracker.getHandler(attributeClass);
373               Object value = handler.unmarshallType(
374                     classInfo,obj,attributeName,marshalledValues, stmt.getTimeControl());
375               classInfo.setAttributeValue(obj,attributeName,value);
376               break;
377            case TYPE_OBJECT:
378               // Handle null
379               if ( attributeValue == null )
380               {
381                  classInfo.setAttributeValue(obj,attributeName,null);
382                  break;
383               }
384               // Get object from list
385               Object relatedObj = unmarshalledObjects.get(attributeValue);
386               classInfo.setAttributeValue(obj,attributeName,relatedObj);
387               if ( relatedObj == null )
388               {
389                  if ( logger.isDebugEnabled() )
390                     logger.debug("referred object of id: "+attributeValue+" not found, currently unmarshalled objects: "+unmarshalledObjects);
391                  // Remember with ids entry. An entry holds all necessary
392                  // information for a single attribute to reconstruct
393                  // it's objects for all referrers:
394                  // - classinfo: of attribute declared type (for select)
395                  // - ids: all ids of referred objects
396                  // - objects: indexed by referred object id, hold a set
397                  //   of objects which need the specified referred object
398                  IdsEntry idsEntry = (IdsEntry) missingAttributes.get(attributeName);
399                  if ( idsEntry == null )
400                  {
401                     idsEntry = new IdsEntry(new HashMap(),new HashSet(),classInfo);
402                     missingAttributes.put(attributeName,idsEntry);
403                  }
404                  idsEntry.ids.add(attributeValue);
405                  List objectsSet = (List) idsEntry.objects.get(attributeValue);
406                  if ( objectsSet == null )
407                  {
408                     objectsSet = new ArrayList();
409                     idsEntry.objects.put(attributeValue,objectsSet);
410                  }
411                  objectsSet.add(obj);
412               }
413               break;
414            default:
415               throw new StoreException("attribute: "+attributeName+"'s type was not valid.");
416         }
417      } // Iteration over attributes
418      return obj;
419      // }}}
420   }
421 
422   public void handle(PersistenceEvent event)
423   {
424      if ( (event instanceof ModifyObjectEvent) || 
425            (event instanceof CreateObjectEvent) ||
426            (event instanceof DeleteObjectEvent) )
427      {
428         // Get the table name for the object
429         Object object = ((ObjectEvent) event).getObject();
430         ClassInfo classInfo = classTracker.getClassInfo(object.getClass(),object);
431         String tableName = schemaManager.getTableName(classInfo.getSourceEntry());
432         // Get transaction
433         Transaction tx = transactionTracker.getTransaction(TransactionTracker.TX_OPTIONAL);
434         // Object was modified, enter into the transaction map
435         Set<String> modifiedTables = transactionTables.get(tx);
436         if ( modifiedTables == null )
437         {
438            modifiedTables = new HashSet<String>();
439            transactionTables.put(tx,modifiedTables);
440         }
441         modifiedTables.add(tableName);
442      }
443      if ( (event instanceof TransactionCommittedEvent) ||
444            (event instanceof TransactionRolledbackEvent) )
445      {
446         Transaction tx = ((TransactionEvent) event).getTransaction();
447         transactionTables.remove(tx);
448      }
449   }
450   
451   /**
452    * Internal loading.
453    */
454   public SearchResult find(QueryStatement stmt, Limits limits, Map unmarshalledObjects)
455   {
456      // {{{ Internal loading code
457      if ( unmarshalledObjects == null )
458         unmarshalledObjects = new HashMap();
459      Transaction transaction = transactionTracker.getTransaction(TransactionTracker.TX_REQUIRED);
460      transaction.begin();
461      TransactionStatistics startStats = new TransactionStatistics();
462      startStats.add(transaction.getStats());
463      long startTime = System.currentTimeMillis();
464      logger.debug("called store internal find.");
465      try
466      {
467         // If the query is a view query, then return raw map format,
468         // else get the main term which is in this case always the
469         // class which to select.
470         if ( stmt.getMode() == QueryStatement.MODE_VIEW )
471            return find(stmt,limits);
472         TableTerm mainTerm = (TableTerm) stmt.getSelectTerms().get(0);
473         SpecifiedTableTerm specifiedMainTerm = stmt.getSpecifiedTerm(mainTerm);
474         ClassInfo classInfo = classTracker.getClassInfo(
475               schemaManager.getClassEntry(mainTerm.getTableName()));
476         if ( classInfo == null )
477            throw new StoreException("no class found for table name: "+mainTerm.getTableName());
478         // Run the real database search
479         logger.debug("find running real select statement.");
480         SearchResult rawResult = find(stmt,limits);
481         // Take the raw data and umarshall them into objects
482         logger.debug("find unmarshalling objects.");
483         SearchResult cookedResult = new SearchResult();
484         HashMap missingAttributes = new HashMap();
485         cookedResult.setResultSize(rawResult.getResultSize());
486         ArrayList cookedResultList = new ArrayList();
487         cookedResult.setResult(cookedResultList);
488         for ( int i=0; i<rawResult.getResult().size(); i++ )
489         {
490            // Get values
491            Map marshalledValues = (Map) rawResult.getResult().get(i);
492            // If object already unmarshalled, then get from list,
493            // else instantiate
494            Object obj = unmarshalledObjects.get(marshalledValues.get("persistence_id"));
495            if ( obj == null )
496            {
497               if ( logger.isDebugEnabled() )
498                  logger.debug("got marshalled values: "+marshalledValues);
499               // Instantiate and unmarshall object
500               ClassInfo localClassInfo = classInfo;
501               if ( specifiedMainTerm.getRelatedLeftTerms().size() > 0 )
502               {
503                  // If there were left join tables, try to get the
504                  // correct class. This means, that the object
505                  // can be the subclass of queried class, and not
506                  // exactly that. We can determine the exact class
507                  // from the persistence id.
508                  Long persistenceId = (Long) marshalledValues.get("persistence_id");
509                  ClassEntry localClassEntry = classTracker.getClassEntry(new Identifier(persistenceId).getClassId());
510                  localClassInfo = classTracker.getClassInfo(localClassEntry);
511               }
512               // Unmarshall, with the exact class info given
513               obj = unmarshallObject(localClassInfo,marshalledValues,
514                     unmarshalledObjects,missingAttributes,stmt);
515            }
516            // Add object to result list. The 'obj' is an umarshalled full
517            // object, which is gethered from the main table of the query.
518            // How ever, if there are other referenced attributes the
519            // query should return, then we do the whole thing into a Map.
520            // The object itself will have the key 'object' in this case.
521            if ( stmt.getSelectTerms().size() > 1 )
522            {
523               // There are other attributes the caller wants, so
524               // do the whole thing into a Map. Insert all wanted attributes,
525               // and the unmarshalled main object too.
526               HashMap resultObj  = new HashMap();
527               for ( int o=1; o<stmt.getSelectTerms().size(); o++ )
528               {
529                  ReferenceTerm refTerm = (ReferenceTerm) stmt.getSelectTerms().get(o);
530                  resultObj.put(refTerm.getColumnFinalName(),marshalledValues.get(refTerm.getColumnFinalName().toLowerCase()));
531               }
532               resultObj.put("object",obj);
533               cookedResultList.add(resultObj);
534            } else {
535               // There was just the object, so insert it into the result
536               // list, just in itself.
537               cookedResultList.add(obj);
538            }
539         }
540         // Load all referred objects for all classes which were unmarshalled,
541         // the missing list was assembled in the unmarshall code.
542         Iterator missingAttributesIterator = missingAttributes.entrySet().iterator();
543         while ( missingAttributesIterator.hasNext() )
544         {
545            // Get all necessary meta-data
546            Map.Entry entry = (Map.Entry) missingAttributesIterator.next();
547            String attributeName = entry.getKey().toString();
548            IdsEntry idsEntry = (IdsEntry) entry.getValue();
549            Class selectClass = idsEntry.classInfo.getAttributeType(attributeName);
550            // We got the class of the object, so we select all objects to
551            // this attribute into a map keyed with the persistence id.
552            HashMap referredObjects = new HashMap();
553            if ( logger.isDebugEnabled() )
554               logger.debug("getting member attribute: "+selectClass+", for ids: "+idsEntry.ids);
555            List referredObjectList = find("find member("+selectClass.getName()+") where member in ?",new Object[] {idsEntry.ids},null,unmarshalledObjects);
556            Iterator referredObjectIterator = referredObjectList.iterator();
557            while ( referredObjectIterator.hasNext() )
558            {
559               Object referredObject = referredObjectIterator.next();
560               referredObjects.put(objectTracker.getIdentifier(referredObject),referredObject);
561            }
562            // Now fill in this attribute with the ready referred objects
563            Iterator objectEntryIterator = idsEntry.objects.entrySet().iterator();
564            while ( objectEntryIterator.hasNext() )
565            {
566               Map.Entry objectEntry = (Map.Entry) objectEntryIterator.next();
567               Object referredObject = referredObjects.get(objectEntry.getKey());
568               // Now set to all referring objects
569               Iterator objectIterator = ((List) objectEntry.getValue()).iterator();
570               while ( objectIterator.hasNext() )
571               {
572                  Object referrerObject = objectIterator.next();
573                  ClassInfo referrerClassInfo = classTracker.getClassInfo(referrerObject.getClass(),referrerObject);
574                  referrerClassInfo.setAttributeValue(referrerObject,attributeName,referredObject);
575               }
576            }
577         }
578         // Debug code
579         if ( operationsLogger.isDebugEnabled() )
580         {
581            TransactionStatistics stats = new TransactionStatistics();
582            stats.add(transaction.getStats());
583            stats.substract(startStats);
584            operationsLogger.debug("operation find: "+stmt.getOriginalStatement()+", "+stats);
585            if ( operationsLogger.isTraceEnabled() )
586               operationsLogger.trace("previous operation trace:",new Exception("trace"));
587         }
588         // Return result
589         logger.debug("find returning result list");
590         return cookedResult;
591      } catch ( StoreException e ) {
592         transaction.markRollbackOnly();
593         logger.error("throwing store exception",e);
594         throw e;
595      } catch ( Throwable e ) {
596         transaction.markRollbackOnly();
597         logger.error("throwing unexpected exception",e);
598         throw new StoreException("unexpected exception",e);
599      } finally {
600         transaction.commit();
601         // Add to statistics
602         long endTime = System.currentTimeMillis();
603         synchronized ( queryStatistics )
604         {
605            queryStatistics.setQueryTime(queryStatistics.getQueryTime()+(endTime-startTime));
606         }
607      }
608      // }}}
609   }
610 
611   private static class IdsEntry
612   {
613      public Set ids;
614      public ClassInfo classInfo;
615      public Map objects;
616      
617      public IdsEntry(Map objects, Set ids, ClassInfo classInfo)
618      {
619         this.objects=objects;
620         this.ids=ids;
621         this.classInfo=classInfo;
622      }
623   }
624 
625}
626 
627 
628 

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