Coverage Report - org.apache.ojb.odmg.collections.DSetImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
DSetImpl
N/A
N/A
1.762
 
 1  
 package org.apache.ojb.odmg.collections;
 2  
 
 3  
 /* Copyright 2002-2005 The Apache Software Foundation
 4  
  *
 5  
  * Licensed under the Apache License, Version 2.0 (the "License");
 6  
  * you may not use this file except in compliance with the License.
 7  
  * You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 import java.io.Serializable;
 19  
 import java.util.AbstractSet;
 20  
 import java.util.ArrayList;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Vector;
 24  
 import java.util.Collection;
 25  
 
 26  
 import org.apache.ojb.broker.PBKey;
 27  
 import org.apache.ojb.broker.PersistenceBroker;
 28  
 import org.apache.ojb.broker.PersistenceBrokerAware;
 29  
 import org.apache.ojb.broker.PersistenceBrokerException;
 30  
 import org.apache.ojb.broker.ManageableCollection;
 31  
 import org.apache.ojb.broker.core.ValueContainer;
 32  
 import org.apache.ojb.broker.metadata.ClassDescriptor;
 33  
 import org.apache.ojb.broker.metadata.FieldDescriptor;
 34  
 import org.apache.ojb.broker.query.Criteria;
 35  
 import org.apache.ojb.broker.query.Query;
 36  
 import org.apache.ojb.broker.query.QueryByCriteria;
 37  
 import org.apache.ojb.broker.util.logging.Logger;
 38  
 import org.apache.ojb.broker.util.logging.LoggerFactory;
 39  
 import org.apache.ojb.odmg.PBCapsule;
 40  
 import org.apache.ojb.odmg.TransactionImpl;
 41  
 import org.apache.ojb.odmg.TxManagerFactory;
 42  
 import org.apache.ojb.odmg.RuntimeObject;
 43  
 import org.apache.ojb.odmg.oql.OQLQueryImpl;
 44  
 import org.odmg.DCollection;
 45  
 import org.odmg.DList;
 46  
 import org.odmg.DSet;
 47  
 import org.odmg.ODMGRuntimeException;
 48  
 import org.odmg.OQLQuery;
 49  
 import org.odmg.Transaction;
 50  
 
 51  
 
 52  
 /**
 53  
  *
 54  
  */
 55  
 public class DSetImpl extends AbstractSet implements DSet, Serializable, PersistenceBrokerAware, ManageableCollection
 56  
 {
 57  
         private static final long serialVersionUID = -4459673364598652639L;
 58  
 
 59  
     private transient Logger log;
 60  
 
 61  
     private Integer id;
 62  
     private List elements;
 63  
 
 64  
     private PBKey pbKey;
 65  
 
 66  
     /**
 67  
      * Used by PB-Kernel to instantiate ManageableCollections
 68  
      * FOR INTERNAL USE ONLY
 69  
      */
 70  
     public DSetImpl()
 71  
     {
 72  
         super();
 73  
         elements = new ArrayList();
 74  
 //        if(getTransaction() == null)
 75  
 //        {
 76  
 //            throw new TransactionNotInProgressException("Materialization of DCollection instances must be done" +
 77  
 //                    " within a odmg-tx");
 78  
 //        }
 79  
         getPBKey();
 80  
     }
 81  
 
 82  
     /**
 83  
      * DSetImpl constructor comment.
 84  
      */
 85  
     public DSetImpl(PBKey pbKey)
 86  
     {
 87  
         this();
 88  
         this.pbKey = pbKey;
 89  
     }
 90  
 
 91  
     protected Logger getLog()
 92  
     {
 93  
         if (log == null)
 94  
         {
 95  
             log = LoggerFactory.getLogger(DSetImpl.class);
 96  
         }
 97  
         return log;
 98  
     }
 99  
 
 100  
     private DSetEntry prepareEntry(Object obj)
 101  
     {
 102  
         return new DSetEntry(this, obj);
 103  
     }
 104  
 
 105  
     protected TransactionImpl getTransaction()
 106  
     {
 107  
         return TxManagerFactory.instance().getTransaction();
 108  
     }
 109  
 
 110  
     protected boolean checkForOpenTransaction(TransactionImpl tx)
 111  
     {
 112  
         boolean result = false;
 113  
         if(tx != null && tx.isOpen())
 114  
         {
 115  
             result = true;
 116  
         }
 117  
         return result;
 118  
     }
 119  
 
 120  
     public PBKey getPBKey()
 121  
     {
 122  
         if(pbKey == null)
 123  
         {
 124  
             TransactionImpl tx = getTransaction();
 125  
             if(tx != null && tx.isOpen())
 126  
             {
 127  
                 pbKey = tx.getBroker().getPBKey();
 128  
             }
 129  
         }
 130  
         return pbKey;
 131  
     }
 132  
 
 133  
     public void setPBKey(PBKey pbKey)
 134  
     {
 135  
         this.pbKey = pbKey;
 136  
     }
 137  
 
 138  
     public boolean remove(Object o)
 139  
     {
 140  
         return super.remove(o);
 141  
     }
 142  
 
 143  
     public boolean removeAll(Collection c)
 144  
     {
 145  
         return super.removeAll(c);
 146  
     }
 147  
 
 148  
     public boolean add(Object o)
 149  
     {
 150  
         if (!this.contains(o))
 151  
         {
 152  
             DSetEntry entry = prepareEntry(o);
 153  
             elements.add(entry);
 154  
             // if we are in a transaction: get locks !
 155  
             TransactionImpl tx = getTransaction();
 156  
             if ((tx != null) && (tx.isOpen()))
 157  
             {
 158  
                 List regList = tx.getRegistrationList();
 159  
                 RuntimeObject rt = new RuntimeObject(this, tx);
 160  
                 tx.lockAndRegister(rt, Transaction.WRITE, false, regList);
 161  
 
 162  
                 rt = new RuntimeObject(o, tx);
 163  
                 tx.lockAndRegister(rt, Transaction.READ, regList);
 164  
 
 165  
                 rt = new RuntimeObject(entry, tx, true);
 166  
                 tx.lockAndRegister(rt, Transaction.WRITE, false, regList);
 167  
             }
 168  
             return true;
 169  
         }
 170  
         else
 171  
         {
 172  
             return false;
 173  
         }
 174  
     }
 175  
 
 176  
     /**
 177  
      * Create a new <code>DSet</code> object that contains the elements of this
 178  
      * collection minus the elements in <code>otherSet</code>.
 179  
      * @param        otherSet        A set containing elements that should not be in the result set.
 180  
      * @return        A newly created <code>DSet</code> instance that contains the elements
 181  
      * of this set minus those elements in <code>otherSet</code>.
 182  
      */
 183  
     public DSet difference(DSet otherSet)
 184  
     {
 185  
         DSetImpl result = new DSetImpl(getPBKey());
 186  
         Iterator iter = this.iterator();
 187  
         while (iter.hasNext())
 188  
         {
 189  
             Object candidate = iter.next();
 190  
             if (!otherSet.contains(candidate))
 191  
             {
 192  
                 result.add(candidate);
 193  
             }
 194  
         }
 195  
         return result;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Determines whether there is an element of the collection that evaluates to true
 200  
      * for the predicate.
 201  
      * @param        predicate        An OQL boolean query predicate.
 202  
      * @return        True if there is an element of the collection that evaluates to true
 203  
      * for the predicate, otherwise false.
 204  
      * @exception        org.odmg.QueryInvalidException        The query predicate is invalid.
 205  
      */
 206  
     public boolean existsElement(String predicate) throws org.odmg.QueryInvalidException
 207  
     {
 208  
         DList results = (DList) this.query(predicate);
 209  
         if (results == null || results.size() == 0)
 210  
             return false;
 211  
         else
 212  
             return true;
 213  
     }
 214  
 
 215  
     public List getElements()
 216  
     {
 217  
         return elements;
 218  
     }
 219  
 
 220  
     public void setElements(List elements)
 221  
     {
 222  
         this.elements = elements;
 223  
     }
 224  
 
 225  
     public Integer getId()
 226  
     {
 227  
         return id;
 228  
     }
 229  
 
 230  
     /**
 231  
      * Create a new <code>DSet</code> object that is the set intersection of this
 232  
      * <code>DSet</code> object and the set referenced by <code>otherSet</code>.
 233  
      * @param        otherSet        The other set to be used in the intersection operation.
 234  
      * @return        A newly created <code>DSet</code> instance that contains the
 235  
      * intersection of the two sets.
 236  
      */
 237  
     public DSet intersection(DSet otherSet)
 238  
     {
 239  
         DSet union = this.union(otherSet);
 240  
         DSetImpl result = new DSetImpl(getPBKey());
 241  
         Iterator iter = union.iterator();
 242  
         while (iter.hasNext())
 243  
         {
 244  
             Object candidate = iter.next();
 245  
             if (this.contains(candidate) && otherSet.contains(candidate))
 246  
             {
 247  
                 result.add(candidate);
 248  
             }
 249  
         }
 250  
         return result;
 251  
     }
 252  
 
 253  
     /**
 254  
      * Returns an iterator over the elements in this collection.  There are no
 255  
      * guarantees concerning the order in which the elements are returned
 256  
      * (unless this collection is an instance of some class that provides a
 257  
      * guarantee).
 258  
      *
 259  
      * @return an <tt>Iterator</tt> over the elements in this collection
 260  
      */
 261  
     public Iterator iterator()
 262  
     {
 263  
         return new DSetIterator(this);
 264  
     }
 265  
 
 266  
     /**
 267  
      * Determine whether this set is a proper subset of the set referenced by
 268  
      * <code>otherSet</code>.
 269  
      * @param        otherSet        Another set.
 270  
      * @return True if this set is a proper subset of the set referenced by
 271  
      * <code>otherSet</code>, otherwise false.
 272  
      */
 273  
     public boolean properSubsetOf(org.odmg.DSet otherSet)
 274  
     {
 275  
         return (this.size() > 0 && this.size() < otherSet.size() && this.subsetOf(otherSet));
 276  
     }
 277  
 
 278  
     /**
 279  
      * Determine whether this set is a proper superset of the set referenced by
 280  
      * <code>otherSet</code>.
 281  
      * @param        otherSet        Another set.
 282  
      * @return True if this set is a proper superset of the set referenced by
 283  
      * <code>otherSet</code>, otherwise false.
 284  
      */
 285  
     public boolean properSupersetOf(org.odmg.DSet otherSet)
 286  
     {
 287  
         return (otherSet.size() > 0 && otherSet.size() < this.size() && this.supersetOf(otherSet));
 288  
     }
 289  
 
 290  
     /**
 291  
      * Evaluate the boolean query predicate for each element of the collection and
 292  
      * return a new collection that contains each element that evaluated to true.
 293  
      * @param        predicate        An OQL boolean query predicate.
 294  
      * @return        A new collection containing the elements that evaluated true for the predicate.
 295  
      * @exception        org.odmg.QueryInvalidException        The query predicate is invalid.
 296  
      */
 297  
     public DCollection query(String predicate) throws org.odmg.QueryInvalidException
 298  
     {
 299  
         // 1.build complete OQL statement
 300  
         String oql = "select all from java.lang.Object where " + predicate;
 301  
         TransactionImpl tx = getTransaction();
 302  
 
 303  
         OQLQuery predicateQuery = tx.getImplementation().newOQLQuery();
 304  
 
 305  
         PBCapsule capsule = new PBCapsule(tx.getImplementation().getCurrentPBKey(), tx);
 306  
         PersistenceBroker broker = capsule.getBroker();
 307  
 
 308  
         try
 309  
         {
 310  
             predicateQuery.create(oql);
 311  
             Query pQ = ((OQLQueryImpl) predicateQuery).getQuery();
 312  
             Criteria pCrit = pQ.getCriteria();
 313  
 
 314  
             Criteria allElementsCriteria = this.getPkCriteriaForAllElements(broker);
 315  
             // join selection of elements with predicate criteria:
 316  
             pCrit.addAndCriteria(allElementsCriteria);
 317  
             Class clazz = this.getElementsExtentClass(broker);
 318  
             Query q = new QueryByCriteria(clazz, pCrit);
 319  
             if (log.isDebugEnabled()) log.debug(q.toString());
 320  
             // 2. perfom query
 321  
             return (DSetImpl) broker.getCollectionByQuery(DSetImpl.class, q);
 322  
         }
 323  
         catch (PersistenceBrokerException e)
 324  
         {
 325  
             throw new ODMGRuntimeException(e.getMessage());
 326  
         }
 327  
         finally
 328  
         {
 329  
             capsule.destroy();
 330  
         }
 331  
     }
 332  
 
 333  
     private Criteria getPkCriteriaForAllElements(PersistenceBroker broker)
 334  
     {
 335  
         try
 336  
         {
 337  
             Criteria crit = null;
 338  
             for (int i = 0; i < elements.size(); i++)
 339  
             {
 340  
                 DListEntry entry = (DListEntry) elements.get(i);
 341  
                 Object obj = entry.getRealSubject();
 342  
                 ClassDescriptor cld = broker.getClassDescriptor(obj.getClass());
 343  
 
 344  
                 FieldDescriptor[] pkFields = cld.getPkFields();
 345  
                 ValueContainer[] pkValues = broker.serviceBrokerHelper().getKeyValues(cld, obj);
 346  
 
 347  
                 Criteria criteria = new Criteria();
 348  
                 for (int j = 0; j < pkFields.length; j++)
 349  
                 {
 350  
                     FieldDescriptor fld = pkFields[j];
 351  
                     criteria.addEqualTo(fld.getPersistentField().getName(), pkValues[j].getValue());
 352  
                 }
 353  
 
 354  
                 if (crit == null)
 355  
                     crit = criteria;
 356  
                 else
 357  
                     crit.addOrCriteria(criteria);
 358  
             }
 359  
             return crit;
 360  
         }
 361  
         catch (PersistenceBrokerException e)
 362  
         {
 363  
             log.error(e);
 364  
             return null;
 365  
         }
 366  
     }
 367  
 
 368  
     private Class getElementsExtentClass(PersistenceBroker broker) throws PersistenceBrokerException
 369  
     {
 370  
         // we ll have to compute the most general extent class here !!!
 371  
         DListEntry entry = (DListEntry) elements.get(0);
 372  
         Class elementsClass = entry.getRealSubject().getClass();
 373  
         Class extentClass = broker.getTopLevelClass(elementsClass);
 374  
         return extentClass;
 375  
     }
 376  
 
 377  
 
 378  
     /**
 379  
      * Access all of the elements of the collection that evaluate to true for the
 380  
      * provided query predicate.
 381  
      * @param        predicate        An OQL boolean query predicate.
 382  
      * @return        An iterator used to iterate over the elements that evaluated true for the predicate.
 383  
      * @exception        org.odmg.QueryInvalidException        The query predicate is invalid.
 384  
      */
 385  
     public Iterator select(String predicate) throws org.odmg.QueryInvalidException
 386  
     {
 387  
         return this.query(predicate).iterator();
 388  
     }
 389  
 
 390  
     /**
 391  
      * Selects the single element of the collection for which the provided OQL query
 392  
      * predicate is true.
 393  
      * @param        predicate        An OQL boolean query predicate.
 394  
      * @return The element that evaluates to true for the predicate. If no element
 395  
      * evaluates to true, null is returned.
 396  
      * @exception        org.odmg.QueryInvalidException        The query predicate is invalid.
 397  
      */
 398  
     public Object selectElement(String predicate) throws org.odmg.QueryInvalidException
 399  
     {
 400  
         return ((DList) this.query(predicate)).get(0);
 401  
     }
 402  
 
 403  
     /**
 404  
      * Sets the elements.
 405  
      * @param elements The elements to set
 406  
      */
 407  
     public void setElements(Vector elements)
 408  
     {
 409  
         this.elements = elements;
 410  
     }
 411  
 
 412  
     /**
 413  
      * Sets the id.
 414  
      * @param id The id to set
 415  
      */
 416  
     public void setId(Integer id)
 417  
     {
 418  
         this.id = id;
 419  
     }
 420  
 
 421  
     /**
 422  
      * Returns the number of elements in this collection.  If this collection
 423  
      * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
 424  
      * <tt>Integer.MAX_VALUE</tt>.
 425  
      *
 426  
      * @return the number of elements in this collection
 427  
      */
 428  
     public int size()
 429  
     {
 430  
         return elements.size();
 431  
     }
 432  
 
 433  
     /**
 434  
      * Determine whether this set is a subset of the set referenced by <code>otherSet</code>.
 435  
      * @param        otherSet        Another set.
 436  
      * @return True if this set is a subset of the set referenced by <code>otherSet</code>,
 437  
      * otherwise false.
 438  
      */
 439  
     public boolean subsetOf(DSet otherSet)
 440  
     {
 441  
         return otherSet.containsAll(this);
 442  
     }
 443  
 
 444  
     /**
 445  
      * Determine whether this set is a superset of the set referenced by <code>otherSet</code>.
 446  
      * @param        otherSet        Another set.
 447  
      * @return True if this set is a superset of the set referenced by <code>otherSet</code>,
 448  
      * otherwise false.
 449  
      */
 450  
     public boolean supersetOf(DSet otherSet)
 451  
     {
 452  
         return this.containsAll(otherSet);
 453  
     }
 454  
 
 455  
     /**
 456  
      * Create a new <code>DSet</code> object that is the set union of this
 457  
      * <code>DSet</code> object and the set referenced by <code>otherSet</code>.
 458  
      * @param        otherSet        The other set to be used in the union operation.
 459  
      * @return        A newly created <code>DSet</code> instance that contains the union of the two sets.
 460  
      */
 461  
     public DSet union(DSet otherSet)
 462  
     {
 463  
         DSetImpl result = new DSetImpl(getPBKey());
 464  
         result.addAll(this);
 465  
         result.addAll(otherSet);
 466  
         return result;
 467  
     }
 468  
 
 469  
 
 470  
     //***************************************************************
 471  
     // ManageableCollection interface
 472  
     //***************************************************************
 473  
 
 474  
     /**
 475  
      * add a single Object to the Collection. This method is used during reading Collection elements
 476  
      * from the database. Thus it is is save to cast anObject to the underlying element type of the
 477  
      * collection.
 478  
      */
 479  
     public void ojbAdd(Object anObject)
 480  
     {
 481  
         DSetEntry entry = prepareEntry(anObject);
 482  
         entry.setPosition(elements.size());
 483  
         elements.add(entry);
 484  
     }
 485  
 
 486  
     /**
 487  
      * adds a Collection to this collection. Used in reading Extents from the Database.
 488  
      * Thus it is save to cast otherCollection to this.getClass().
 489  
      */
 490  
     public void ojbAddAll(ManageableCollection otherCollection)
 491  
     {
 492  
         // don't use this to avoid locking
 493  
         // this.addAll((DListImpl) otherCollection);
 494  
         Iterator it = otherCollection.ojbIterator();
 495  
         while (it.hasNext())
 496  
         {
 497  
             ojbAdd(it.next());
 498  
         }
 499  
     }
 500  
 
 501  
     public void afterStore(PersistenceBroker broker) throws PersistenceBrokerException
 502  
     {
 503  
     }
 504  
 
 505  
     /**
 506  
      * returns an Iterator over all elements in the collection. Used during store and delete Operations.
 507  
      * If the implementor does not return an iterator over ALL elements, OJB cannot store and delete all elements properly.
 508  
      */
 509  
     public Iterator ojbIterator()
 510  
     {
 511  
         return this.iterator();
 512  
     }
 513  
 
 514  
     //***************************************************************
 515  
     // PersistenceBrokerAware interface
 516  
     //***************************************************************
 517  
 
 518  
     /**
 519  
      * prepare itself for persistence. Each DList entry generates an
 520  
      * {@link org.apache.ojb.broker.Identity} for the wrapped persistent
 521  
      * object.
 522  
      */
 523  
     public void beforeInsert(PersistenceBroker broker) throws PersistenceBrokerException
 524  
     {
 525  
 //        Iterator it = elements.iterator();
 526  
 //        DSetEntry entry;
 527  
 //        while (it.hasNext())
 528  
 //        {
 529  
 //            entry = (DSetEntry) it.next();
 530  
 //            entry.prepareForPersistency(broker);
 531  
 //        }
 532  
     }
 533  
 
 534  
     /**
 535  
      * noop
 536  
      */
 537  
     public void beforeUpdate(PersistenceBroker broker) throws PersistenceBrokerException
 538  
     {
 539  
     }
 540  
 
 541  
     /**
 542  
      * noop
 543  
      */
 544  
     public void beforeDelete(PersistenceBroker broker) throws PersistenceBrokerException
 545  
     {
 546  
     }
 547  
 
 548  
     /**
 549  
      * noop
 550  
      */
 551  
     public void afterUpdate(PersistenceBroker broker) throws PersistenceBrokerException
 552  
     {
 553  
     }
 554  
 
 555  
     /**
 556  
      * noop
 557  
      */
 558  
     public void afterInsert(PersistenceBroker broker) throws PersistenceBrokerException
 559  
     {
 560  
     }
 561  
 
 562  
     /**
 563  
      * noop
 564  
      */
 565  
     public void afterDelete(PersistenceBroker broker) throws PersistenceBrokerException
 566  
     {
 567  
     }
 568  
 
 569  
     /**
 570  
      * noop
 571  
      */
 572  
     public void afterLookup(PersistenceBroker broker) throws PersistenceBrokerException
 573  
     {
 574  
     }
 575  
 }