001: package org.apache.ojb.odmg.collections;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.io.Serializable;
019: import java.util.AbstractSet;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Vector;
024: import java.util.Collection;
025:
026: import org.apache.ojb.broker.PBKey;
027: import org.apache.ojb.broker.PersistenceBroker;
028: import org.apache.ojb.broker.PersistenceBrokerAware;
029: import org.apache.ojb.broker.PersistenceBrokerException;
030: import org.apache.ojb.broker.ManageableCollection;
031: import org.apache.ojb.broker.core.ValueContainer;
032: import org.apache.ojb.broker.metadata.ClassDescriptor;
033: import org.apache.ojb.broker.metadata.FieldDescriptor;
034: import org.apache.ojb.broker.query.Criteria;
035: import org.apache.ojb.broker.query.Query;
036: import org.apache.ojb.broker.query.QueryByCriteria;
037: import org.apache.ojb.broker.util.logging.Logger;
038: import org.apache.ojb.broker.util.logging.LoggerFactory;
039: import org.apache.ojb.odmg.PBCapsule;
040: import org.apache.ojb.odmg.TransactionImpl;
041: import org.apache.ojb.odmg.TxManagerFactory;
042: import org.apache.ojb.odmg.RuntimeObject;
043: import org.apache.ojb.odmg.oql.OQLQueryImpl;
044: import org.odmg.DCollection;
045: import org.odmg.DList;
046: import org.odmg.DSet;
047: import org.odmg.ODMGRuntimeException;
048: import org.odmg.OQLQuery;
049: import org.odmg.Transaction;
050:
051: /**
052: *
053: */
054: public class DSetImpl extends AbstractSet implements DSet,
055: Serializable, PersistenceBrokerAware, ManageableCollection {
056: private static final long serialVersionUID = -4459673364598652639L;
057:
058: private transient Logger log;
059:
060: private Integer id;
061: private List elements;
062:
063: private PBKey pbKey;
064:
065: /**
066: * Used by PB-Kernel to instantiate ManageableCollections
067: * FOR INTERNAL USE ONLY
068: */
069: public DSetImpl() {
070: super ();
071: elements = new ArrayList();
072: // if(getTransaction() == null)
073: // {
074: // throw new TransactionNotInProgressException("Materialization of DCollection instances must be done" +
075: // " within a odmg-tx");
076: // }
077: getPBKey();
078: }
079:
080: /**
081: * DSetImpl constructor comment.
082: */
083: public DSetImpl(PBKey pbKey) {
084: this ();
085: this .pbKey = pbKey;
086: }
087:
088: protected Logger getLog() {
089: if (log == null) {
090: log = LoggerFactory.getLogger(DSetImpl.class);
091: }
092: return log;
093: }
094:
095: private DSetEntry prepareEntry(Object obj) {
096: return new DSetEntry(this , obj);
097: }
098:
099: protected TransactionImpl getTransaction() {
100: return TxManagerFactory.instance().getTransaction();
101: }
102:
103: protected boolean checkForOpenTransaction(TransactionImpl tx) {
104: boolean result = false;
105: if (tx != null && tx.isOpen()) {
106: result = true;
107: }
108: return result;
109: }
110:
111: public PBKey getPBKey() {
112: if (pbKey == null) {
113: TransactionImpl tx = getTransaction();
114: if (tx != null && tx.isOpen()) {
115: pbKey = tx.getBroker().getPBKey();
116: }
117: }
118: return pbKey;
119: }
120:
121: public void setPBKey(PBKey pbKey) {
122: this .pbKey = pbKey;
123: }
124:
125: public boolean remove(Object o) {
126: return super .remove(o);
127: }
128:
129: public boolean removeAll(Collection c) {
130: return super .removeAll(c);
131: }
132:
133: public boolean add(Object o) {
134: if (!this .contains(o)) {
135: DSetEntry entry = prepareEntry(o);
136: elements.add(entry);
137: // if we are in a transaction: get locks !
138: TransactionImpl tx = getTransaction();
139: if ((tx != null) && (tx.isOpen())) {
140: List regList = tx.getRegistrationList();
141: RuntimeObject rt = new RuntimeObject(this , tx);
142: tx.lockAndRegister(rt, Transaction.WRITE, false,
143: regList);
144:
145: rt = new RuntimeObject(o, tx);
146: tx.lockAndRegister(rt, Transaction.READ, regList);
147:
148: rt = new RuntimeObject(entry, tx, true);
149: tx.lockAndRegister(rt, Transaction.WRITE, false,
150: regList);
151: }
152: return true;
153: } else {
154: return false;
155: }
156: }
157:
158: /**
159: * Create a new <code>DSet</code> object that contains the elements of this
160: * collection minus the elements in <code>otherSet</code>.
161: * @param otherSet A set containing elements that should not be in the result set.
162: * @return A newly created <code>DSet</code> instance that contains the elements
163: * of this set minus those elements in <code>otherSet</code>.
164: */
165: public DSet difference(DSet otherSet) {
166: DSetImpl result = new DSetImpl(getPBKey());
167: Iterator iter = this .iterator();
168: while (iter.hasNext()) {
169: Object candidate = iter.next();
170: if (!otherSet.contains(candidate)) {
171: result.add(candidate);
172: }
173: }
174: return result;
175: }
176:
177: /**
178: * Determines whether there is an element of the collection that evaluates to true
179: * for the predicate.
180: * @param predicate An OQL boolean query predicate.
181: * @return True if there is an element of the collection that evaluates to true
182: * for the predicate, otherwise false.
183: * @exception org.odmg.QueryInvalidException The query predicate is invalid.
184: */
185: public boolean existsElement(String predicate)
186: throws org.odmg.QueryInvalidException {
187: DList results = (DList) this .query(predicate);
188: if (results == null || results.size() == 0)
189: return false;
190: else
191: return true;
192: }
193:
194: public List getElements() {
195: return elements;
196: }
197:
198: public void setElements(List elements) {
199: this .elements = elements;
200: }
201:
202: public Integer getId() {
203: return id;
204: }
205:
206: /**
207: * Create a new <code>DSet</code> object that is the set intersection of this
208: * <code>DSet</code> object and the set referenced by <code>otherSet</code>.
209: * @param otherSet The other set to be used in the intersection operation.
210: * @return A newly created <code>DSet</code> instance that contains the
211: * intersection of the two sets.
212: */
213: public DSet intersection(DSet otherSet) {
214: DSet union = this .union(otherSet);
215: DSetImpl result = new DSetImpl(getPBKey());
216: Iterator iter = union.iterator();
217: while (iter.hasNext()) {
218: Object candidate = iter.next();
219: if (this .contains(candidate)
220: && otherSet.contains(candidate)) {
221: result.add(candidate);
222: }
223: }
224: return result;
225: }
226:
227: /**
228: * Returns an iterator over the elements in this collection. There are no
229: * guarantees concerning the order in which the elements are returned
230: * (unless this collection is an instance of some class that provides a
231: * guarantee).
232: *
233: * @return an <tt>Iterator</tt> over the elements in this collection
234: */
235: public Iterator iterator() {
236: return new DSetIterator(this );
237: }
238:
239: /**
240: * Determine whether this set is a proper subset of the set referenced by
241: * <code>otherSet</code>.
242: * @param otherSet Another set.
243: * @return True if this set is a proper subset of the set referenced by
244: * <code>otherSet</code>, otherwise false.
245: */
246: public boolean properSubsetOf(org.odmg.DSet otherSet) {
247: return (this .size() > 0 && this .size() < otherSet.size() && this
248: .subsetOf(otherSet));
249: }
250:
251: /**
252: * Determine whether this set is a proper superset of the set referenced by
253: * <code>otherSet</code>.
254: * @param otherSet Another set.
255: * @return True if this set is a proper superset of the set referenced by
256: * <code>otherSet</code>, otherwise false.
257: */
258: public boolean properSupersetOf(org.odmg.DSet otherSet) {
259: return (otherSet.size() > 0 && otherSet.size() < this .size() && this
260: .super setOf(otherSet));
261: }
262:
263: /**
264: * Evaluate the boolean query predicate for each element of the collection and
265: * return a new collection that contains each element that evaluated to true.
266: * @param predicate An OQL boolean query predicate.
267: * @return A new collection containing the elements that evaluated true for the predicate.
268: * @exception org.odmg.QueryInvalidException The query predicate is invalid.
269: */
270: public DCollection query(String predicate)
271: throws org.odmg.QueryInvalidException {
272: // 1.build complete OQL statement
273: String oql = "select all from java.lang.Object where "
274: + predicate;
275: TransactionImpl tx = getTransaction();
276:
277: OQLQuery predicateQuery = tx.getImplementation().newOQLQuery();
278:
279: PBCapsule capsule = new PBCapsule(tx.getImplementation()
280: .getCurrentPBKey(), tx);
281: PersistenceBroker broker = capsule.getBroker();
282:
283: try {
284: predicateQuery.create(oql);
285: Query pQ = ((OQLQueryImpl) predicateQuery).getQuery();
286: Criteria pCrit = pQ.getCriteria();
287:
288: Criteria allElementsCriteria = this
289: .getPkCriteriaForAllElements(broker);
290: // join selection of elements with predicate criteria:
291: pCrit.addAndCriteria(allElementsCriteria);
292: Class clazz = this .getElementsExtentClass(broker);
293: Query q = new QueryByCriteria(clazz, pCrit);
294: if (log.isDebugEnabled())
295: log.debug(q.toString());
296: // 2. perfom query
297: return (DSetImpl) broker.getCollectionByQuery(
298: DSetImpl.class, q);
299: } catch (PersistenceBrokerException e) {
300: throw new ODMGRuntimeException(e.getMessage());
301: } finally {
302: capsule.destroy();
303: }
304: }
305:
306: private Criteria getPkCriteriaForAllElements(
307: PersistenceBroker broker) {
308: try {
309: Criteria crit = null;
310: for (int i = 0; i < elements.size(); i++) {
311: DListEntry entry = (DListEntry) elements.get(i);
312: Object obj = entry.getRealSubject();
313: ClassDescriptor cld = broker.getClassDescriptor(obj
314: .getClass());
315:
316: FieldDescriptor[] pkFields = cld.getPkFields();
317: ValueContainer[] pkValues = broker
318: .serviceBrokerHelper().getKeyValues(cld, obj);
319:
320: Criteria criteria = new Criteria();
321: for (int j = 0; j < pkFields.length; j++) {
322: FieldDescriptor fld = pkFields[j];
323: criteria.addEqualTo(fld.getPersistentField()
324: .getName(), pkValues[j].getValue());
325: }
326:
327: if (crit == null)
328: crit = criteria;
329: else
330: crit.addOrCriteria(criteria);
331: }
332: return crit;
333: } catch (PersistenceBrokerException e) {
334: log.error(e);
335: return null;
336: }
337: }
338:
339: private Class getElementsExtentClass(PersistenceBroker broker)
340: throws PersistenceBrokerException {
341: // we ll have to compute the most general extent class here !!!
342: DListEntry entry = (DListEntry) elements.get(0);
343: Class elementsClass = entry.getRealSubject().getClass();
344: Class extentClass = broker.getTopLevelClass(elementsClass);
345: return extentClass;
346: }
347:
348: /**
349: * Access all of the elements of the collection that evaluate to true for the
350: * provided query predicate.
351: * @param predicate An OQL boolean query predicate.
352: * @return An iterator used to iterate over the elements that evaluated true for the predicate.
353: * @exception org.odmg.QueryInvalidException The query predicate is invalid.
354: */
355: public Iterator select(String predicate)
356: throws org.odmg.QueryInvalidException {
357: return this .query(predicate).iterator();
358: }
359:
360: /**
361: * Selects the single element of the collection for which the provided OQL query
362: * predicate is true.
363: * @param predicate An OQL boolean query predicate.
364: * @return The element that evaluates to true for the predicate. If no element
365: * evaluates to true, null is returned.
366: * @exception org.odmg.QueryInvalidException The query predicate is invalid.
367: */
368: public Object selectElement(String predicate)
369: throws org.odmg.QueryInvalidException {
370: return ((DList) this .query(predicate)).get(0);
371: }
372:
373: /**
374: * Sets the elements.
375: * @param elements The elements to set
376: */
377: public void setElements(Vector elements) {
378: this .elements = elements;
379: }
380:
381: /**
382: * Sets the id.
383: * @param id The id to set
384: */
385: public void setId(Integer id) {
386: this .id = id;
387: }
388:
389: /**
390: * Returns the number of elements in this collection. If this collection
391: * contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
392: * <tt>Integer.MAX_VALUE</tt>.
393: *
394: * @return the number of elements in this collection
395: */
396: public int size() {
397: return elements.size();
398: }
399:
400: /**
401: * Determine whether this set is a subset of the set referenced by <code>otherSet</code>.
402: * @param otherSet Another set.
403: * @return True if this set is a subset of the set referenced by <code>otherSet</code>,
404: * otherwise false.
405: */
406: public boolean subsetOf(DSet otherSet) {
407: return otherSet.containsAll(this );
408: }
409:
410: /**
411: * Determine whether this set is a superset of the set referenced by <code>otherSet</code>.
412: * @param otherSet Another set.
413: * @return True if this set is a superset of the set referenced by <code>otherSet</code>,
414: * otherwise false.
415: */
416: public boolean super setOf(DSet otherSet) {
417: return this .containsAll(otherSet);
418: }
419:
420: /**
421: * Create a new <code>DSet</code> object that is the set union of this
422: * <code>DSet</code> object and the set referenced by <code>otherSet</code>.
423: * @param otherSet The other set to be used in the union operation.
424: * @return A newly created <code>DSet</code> instance that contains the union of the two sets.
425: */
426: public DSet union(DSet otherSet) {
427: DSetImpl result = new DSetImpl(getPBKey());
428: result.addAll(this );
429: result.addAll(otherSet);
430: return result;
431: }
432:
433: //***************************************************************
434: // ManageableCollection interface
435: //***************************************************************
436:
437: /**
438: * add a single Object to the Collection. This method is used during reading Collection elements
439: * from the database. Thus it is is save to cast anObject to the underlying element type of the
440: * collection.
441: */
442: public void ojbAdd(Object anObject) {
443: DSetEntry entry = prepareEntry(anObject);
444: entry.setPosition(elements.size());
445: elements.add(entry);
446: }
447:
448: /**
449: * adds a Collection to this collection. Used in reading Extents from the Database.
450: * Thus it is save to cast otherCollection to this.getClass().
451: */
452: public void ojbAddAll(ManageableCollection otherCollection) {
453: // don't use this to avoid locking
454: // this.addAll((DListImpl) otherCollection);
455: Iterator it = otherCollection.ojbIterator();
456: while (it.hasNext()) {
457: ojbAdd(it.next());
458: }
459: }
460:
461: public void afterStore(PersistenceBroker broker)
462: throws PersistenceBrokerException {
463: }
464:
465: /**
466: * returns an Iterator over all elements in the collection. Used during store and delete Operations.
467: * If the implementor does not return an iterator over ALL elements, OJB cannot store and delete all elements properly.
468: */
469: public Iterator ojbIterator() {
470: return this .iterator();
471: }
472:
473: //***************************************************************
474: // PersistenceBrokerAware interface
475: //***************************************************************
476:
477: /**
478: * prepare itself for persistence. Each DList entry generates an
479: * {@link org.apache.ojb.broker.Identity} for the wrapped persistent
480: * object.
481: */
482: public void beforeInsert(PersistenceBroker broker)
483: throws PersistenceBrokerException {
484: // Iterator it = elements.iterator();
485: // DSetEntry entry;
486: // while (it.hasNext())
487: // {
488: // entry = (DSetEntry) it.next();
489: // entry.prepareForPersistency(broker);
490: // }
491: }
492:
493: /**
494: * noop
495: */
496: public void beforeUpdate(PersistenceBroker broker)
497: throws PersistenceBrokerException {
498: }
499:
500: /**
501: * noop
502: */
503: public void beforeDelete(PersistenceBroker broker)
504: throws PersistenceBrokerException {
505: }
506:
507: /**
508: * noop
509: */
510: public void afterUpdate(PersistenceBroker broker)
511: throws PersistenceBrokerException {
512: }
513:
514: /**
515: * noop
516: */
517: public void afterInsert(PersistenceBroker broker)
518: throws PersistenceBrokerException {
519: }
520:
521: /**
522: * noop
523: */
524: public void afterDelete(PersistenceBroker broker)
525: throws PersistenceBrokerException {
526: }
527:
528: /**
529: * noop
530: */
531: public void afterLookup(PersistenceBroker broker)
532: throws PersistenceBrokerException {
533: }
534: }
|