001: /**
002: * Copyright (C) 2001-2004 France Telecom R&D
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: */package org.objectweb.speedo.genclass.collection;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.Map;
024:
025: import javax.jdo.listener.DetachLifecycleListener;
026:
027: import org.objectweb.jorm.api.PIndexedElem;
028: import org.objectweb.jorm.naming.api.PName;
029: import org.objectweb.jorm.util.api.Loggable;
030: import org.objectweb.speedo.api.Debug;
031: import org.objectweb.speedo.genclass.GenClassAccessor;
032: import org.objectweb.speedo.genclass.GenClassElement;
033: import org.objectweb.speedo.genclass.PIndexedElemIterator;
034: import org.objectweb.speedo.genclass.AbstractGenClassHome;
035: import org.objectweb.speedo.genclass.api.SpeedoGenClassPO;
036: import org.objectweb.speedo.mim.api.DetachedLifeCycle;
037: import org.objectweb.speedo.mim.api.LifeCycle;
038: import org.objectweb.speedo.mim.api.StateItf;
039: import org.objectweb.speedo.mim.api.PersistentObjectItf;
040: import org.objectweb.speedo.pm.api.POManagerItf;
041: import org.objectweb.util.monolog.api.BasicLevel;
042:
043: /**
044: * @author S.Chassande-Barrioz
045: */
046: public class CollectionAccessor extends GenClassAccessor implements
047: Collection {
048:
049: /**
050: * is the internal collection used when the gen class is not active.
051: * When the po is active the 'elements' field is used.
052: */
053: protected Collection collection = null;
054:
055: /**
056: * Instanciates and initializes a new collection with an initial size.
057: */
058: public CollectionAccessor(SpeedoGenClassPO thepo) {
059: super (thepo);
060: collection = (Collection) gcpo.createGenClass();
061: }
062:
063: public String toString() {
064: return "CollectionAccessor: id=" + gcpo.speedoGetGenClassId();
065: }
066:
067: protected boolean duplicatAllowed() {
068: return true;
069: }
070:
071: public GenClassElement speedoRemove2(Object o) {
072: tmpelem.setElement(o); // tmp type = etype.
073: Iterator it = elements.iterator();
074: while (it.hasNext()) {
075: CollectionElem e = (CollectionElem) it.next();
076: if (e.equals(tmpelem)
077: && e.getElemStatus() != PIndexedElem.ELEM_DELETED) {
078: e.setStatus(PIndexedElem.ELEM_DELETED);
079: if (Debug.ON && getLogger() != null) {
080: logger.log(BasicLevel.DEBUG,
081: "speedoRemove2(): removed");
082: }
083: return e;
084: }
085: }
086: if (Debug.ON && getLogger() != null) {
087: logger.log(BasicLevel.DEBUG, "speedoRemove2(): not found");
088: }
089: return null;
090: }
091:
092: public void makePersistent(POManagerItf pm) {
093: if (Debug.ON && getLogger() != null) {
094: logger.log(BasicLevel.DEBUG, "makePersistent");
095: }
096: if (collection.size() > 0) {
097: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
098: .makePersistent(pm, collection.iterator(), null,
099: null);
100: }
101: }
102:
103: public void makePersistentOnAttach(POManagerItf pm, Map map) {
104: if (Debug.ON && getLogger() != null) {
105: logger.log(BasicLevel.DEBUG, "makePersistent");
106: }
107: if (collection.size() > 0) {
108: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
109: .makePersistent(pm, collection.iterator(), null,
110: map);
111: }
112: }
113:
114: public void deletePersistent(POManagerItf pm) {
115: if (Debug.ON && getLogger() != null) {
116: logger.log(BasicLevel.DEBUG, "deletePersistent");
117: }
118: clear();
119: }
120:
121: public void setElements(Object o) {
122: if (Debug.ON && getLogger() != null) {
123: logger.log(BasicLevel.DEBUG, "setElements()");
124: }
125: clear();
126: if (o != null) {
127: addAll(((Collection) o));
128: }
129: }
130:
131: public void loadFieldsFromAccessor(StateItf sa) {
132: if (Debug.ON && getLogger() != null) {
133: logger.log(BasicLevel.DEBUG, "jdoLoadFieldsFromAccessor()");
134: }
135: CollectionAccessor ca = (CollectionAccessor) sa;
136: collection.clear();
137: collection.addAll(ca.collection);
138: supportDelta = ca.supportDelta;
139: elements.clear();
140: elements.addAll(ca.elements);
141: speedoSetStatus(ca.speedoGetStatus());
142: }
143:
144: public void detachCopy(POManagerItf pm, Map map,
145: StateItf fieldsClone, Collection fgHints) {
146: ((CollectionAccessor) fieldsClone).loadFieldsFromAccessor(this );
147: //copy the elements in the collection: collection is no more available when the po is not active
148: ((CollectionAccessor) fieldsClone).collection.clear();
149: //get an interator on the PIndexed elements
150: Iterator it = ((GenClassAccessor) fieldsClone).elements
151: .iterator();
152: while (it.hasNext()) {
153: //for each element of the collection, send the list of fields to load passed as a parameter
154: //indeed, the list sent will be modified (elements processed are removed)
155: Iterator itFgHints = fgHints.iterator();
156: Collection currentFgHints = new ArrayList();
157: while (itFgHints.hasNext()) {
158: currentFgHints.add((String) itFgHints.next());
159: }
160: //get the PIndexElement
161: CollectionElem iElem = (CollectionElem) it.next();
162: //get the object associated
163: Object elem = iElem.getElement((POManagerItf) pm);
164: Object clone = null;
165: //if it is a persistent object, detach it
166: if (elem instanceof PersistentObjectItf) {
167: //get the speedo po associated
168: PersistentObjectItf sp = (PersistentObjectItf) elem;
169: if (map != null)
170: clone = map.get(sp);
171: //detach only if not already done before
172: if (clone == null) {
173: synchronized (currentFgHints) {
174: //get the clone of the speedo po
175: clone = pm.speedoDetachCopy(sp, map,
176: currentFgHints);
177: }
178: }
179: } else {
180: //else, just copy it
181: clone = elem;
182: }
183: //add the clone in the collection of elements reachable when the po is no more active
184: ((CollectionAccessor) fieldsClone).collection.add(clone);
185: }
186: ((GenClassAccessor) fieldsClone)
187: .speedoSetStatus(LifeCycle.TRANSIENT);
188: }
189:
190: public void attachCopy(POManagerItf pm, Map map,
191: StateItf fieldsClone) {
192: CollectionAccessor ca = (CollectionAccessor) fieldsClone;
193: //get an iterator on the PIndexed elements of the collection
194: Iterator it = ca.collection.iterator();
195: while (it.hasNext()) {
196: Object elem = it.next();
197: //if it is a persistent object
198: if (elem instanceof PersistentObjectItf) {
199: //get the detached speedo po
200: PersistentObjectItf spDetached = (PersistentObjectItf) elem;
201: PersistentObjectItf sp = (PersistentObjectItf) map
202: .get(spDetached);
203: if (sp == null) {
204: map.put(spDetached, sp);
205: sp = (PersistentObjectItf) pm.speedoAttachCopy(
206: spDetached, map);
207: }
208: //put the element of the collection attribute in the elements attribute (the opposite of the jdoDetachCopy method)
209: speedoAddOnAttach(sp, false);
210: } else {
211: //just add the java object in the collection
212: speedoAddOnAttach(elem, false);
213: }
214: }
215: }
216:
217: public void refresh(POManagerItf pm, Map map, Collection fgHints) {
218: commonRefreshRetrieve(pm, map, fgHints, true);
219: }
220:
221: public void retrieve(POManagerItf pm, Map map, Collection fgHints) {
222: commonRefreshRetrieve(pm, map, fgHints, false);
223: }
224:
225: /**
226: *
227: * @param pm
228: * @param map
229: * @param fgHints
230: * @param refresh: if true, call refresh, else call retrieve
231: */
232: //TODO: what about refreshing Collection of String, Integer, Date????
233: private void commonRefreshRetrieve(POManagerItf pm, Map map,
234: Collection fgHints, boolean refresh) {
235: //get an interator on the PIndexed elements
236: Iterator it = elements.iterator();
237: while (it.hasNext()) {
238: //get the PIndexElement
239: CollectionElem iElem = (CollectionElem) it.next();
240: //get the po associated
241: PersistentObjectItf sp = (PersistentObjectItf) iElem
242: .getElement(pm);
243: if (map != null && !map.containsKey(sp.getPName())) {
244: synchronized (fgHints) {
245: if (refresh) { //refresh
246: pm.speedoRefresh(sp, map, fgHints);
247: } else { //retrieve
248: pm.speedoRetrieve(sp, map, fgHints);
249: }
250:
251: }
252: }
253: }
254: }
255:
256: // ------------------------------------------------------------------------
257: // IMPLEMENTATION OF THE Collection INTERFACE
258: // ------------------------------------------------------------------------
259:
260: public boolean add(Object o) {
261: if (Debug.ON && getLogger() != null) {
262: logger.log(BasicLevel.DEBUG, "add()");
263: }
264: GenClassElement gce = speedoAdd(o, false);
265:
266: //Send the event about the new element adding
267: if (gce != null) {
268: Object obj = o;
269: if (obj instanceof PName) {
270: obj = gce.getElement(((PersistentObjectItf) gcpo)
271: .speedoGetPOManager());
272: }
273: if (obj instanceof PersistentObjectItf) {
274: gcpo.fireSpeedoElementAdded(obj);
275: }
276: }
277: return gce != null;
278: }
279:
280: public boolean addAll(Collection c) {
281: Iterator it = c.iterator();
282: boolean changed = false;
283: while (it.hasNext()) {
284: changed |= add(it.next());
285: }
286: return changed;
287: }
288:
289: public void clear() {
290: if (elements.size() > 0) {
291: if (Debug.ON && getLogger() != null) {
292: logger.log(BasicLevel.DEBUG, "clear()");
293: }
294: Collection c = new ArrayList(this );
295: Iterator i = c.iterator();
296: while (i.hasNext()) {
297: remove(i.next());
298: }
299: elements.clear(); // efficient, but does not work with relations
300: supportDelta = false;
301: } else {
302: if (Debug.ON && getLogger() != null) {
303: logger.log(BasicLevel.DEBUG,
304: "clear(): empty collection");
305: }
306: }
307: }
308:
309: public boolean contains(Object o) {
310: tmpelem.setElement(o);
311: Iterator it = elements.iterator();
312: while (it.hasNext()) {
313: PIndexedElem e = (PIndexedElem) it.next();
314: if (e.equals(tmpelem)
315: && e.getElemStatus() != PIndexedElem.ELEM_DELETED) {
316: if (Debug.ON && getLogger() != null) {
317: logger.log(BasicLevel.DEBUG, "contains(): yes");
318: }
319: return true;
320: }
321: }
322: if (Debug.ON && getLogger() != null) {
323: logger.log(BasicLevel.DEBUG, "contains(): no");
324: }
325: return false;
326: }
327:
328: public boolean containsAll(Collection c) {
329: Iterator it = c.iterator();
330: while (it.hasNext()) {
331: if (!contains(it.next())) {
332: return false;
333: }
334: }
335: return true;
336: }
337:
338: public boolean equals(Object o) {
339: return (o instanceof Collection)
340: && ((Collection) o).size() == size()
341: && containsAll((Collection) o);
342: }
343:
344: public boolean isEmpty() {
345: if (elements.isEmpty()) {
346: return true;
347: }
348: Iterator it = elements.iterator();
349: // The set is empty if it contains only deleted indexed elements
350: while (it.hasNext()) {
351: if (((PIndexedElem) it.next()).getElemStatus() != PIndexedElem.ELEM_DELETED) {
352: return false;
353: }
354: }
355: return true;
356: }
357:
358: public Iterator iterator() {
359: return new PIndexedElemIterator(elements, this ,
360: ((PersistentObjectItf) gcpo).speedoGetPOManager(),
361: ((Loggable) gcpo).getLogger());
362: }
363:
364: public boolean remove(Object o) {
365: GenClassElement gce = speedoRemove2(o);
366: if (Debug.ON && getLogger() != null) {
367: logger.log(BasicLevel.DEBUG, "remove: gce=" + gce);
368: }
369: if (gce != null) {
370: Object obj = gce.getElement(((PersistentObjectItf) gcpo)
371: .speedoGetPOManager());
372: if (obj != null) {
373: gcpo.fireSpeedoElementRemoved(obj);
374: }
375: }
376: return gce != null;
377: }
378:
379: public boolean removeAll(Collection c) {
380: Iterator it = c.iterator();
381: boolean removed = true;
382: while (it.hasNext()) {
383: removed &= remove(it.next());
384: }
385: return removed;
386: }
387:
388: public boolean retainAll(Collection c) {
389: throw new UnsupportedOperationException();
390: }
391:
392: public int size() {
393: Iterator it = elements.iterator();
394: int size = 0;
395: while (it.hasNext()) {
396: if (((PIndexedElem) it.next()).getElemStatus() != PIndexedElem.ELEM_DELETED) {
397: size++;
398: }
399: }
400: return size;
401: }
402:
403: public Object[] toArray() {
404: ArrayList al = new ArrayList(elements.size());
405: Iterator it = elements.iterator();
406: while (it.hasNext()) {
407: GenClassElement gce = (GenClassElement) it.next();
408: if (gce.getElemStatus() != PIndexedElem.ELEM_DELETED) {
409: al.add(gce.getElement());
410: }
411: }
412: return al.toArray();
413: }
414:
415: public Object[] toArray(Object[] a) {
416: ArrayList al = new ArrayList(elements.size());
417: Iterator it = elements.iterator();
418: while (it.hasNext()) {
419: GenClassElement gce = (GenClassElement) it.next();
420: if (gce.getElemStatus() != PIndexedElem.ELEM_DELETED) {
421: al.add(gce.getElement());
422: }
423: }
424: return al.toArray(a);
425: }
426:
427: // ------------------------------------------------------------------------
428: // IMPLEMENTATION OF THE PGenClassAccessor INTERFACE
429: // ------------------------------------------------------------------------
430:
431: public PIndexedElem createPIndexedElem(GenClassAccessor gca) {
432: return new CollectionElem(gca);
433: }
434:
435: // ------------------------------------------------------------------------
436: // IMPLEMENTATION OF THE SpeedoGenClassCoherence INTERFACE
437: // ------------------------------------------------------------------------
438:
439: public boolean speedoAdd(Object o, Object hints) {
440: return speedoAdd(o, false) != null;
441: }
442:
443: protected GenClassElement speedoAdd(Object o,
444: boolean allowDuplicates) {
445: if (Debug.ON && getLogger() != null) {
446: logger.log(BasicLevel.DEBUG, "speedoAdd(, "
447: + allowDuplicates + ")");
448: }
449: if (o instanceof PersistentObjectItf
450: && !((PersistentObjectItf) o).speedoIsActive()) {
451: //if not detached, then make it persistent
452: if (((PersistentObjectItf) o).speedoGetReferenceState()
453: .getDetachedStatus() == DetachedLifeCycle.DETACHED_NONE) {
454: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
455: .makePersistent(null, (PersistentObjectItf) o,
456: (SpeedoGenClassPO) getSpeedoPO(), null);
457: } else {
458: //attach it
459: //problem the map is re-instanciated on each add...
460: o = getSpeedoPO().speedoGetPOManager()
461: .speedoAttachCopy(o, new HashMap());
462: }
463: }
464: synchronized (this ) {
465: if (!allowDuplicates && contains(o)) {
466: if (Debug.ON && getLogger() != null) {
467: logger.log(BasicLevel.DEBUG, "speedoAdd(, "
468: + allowDuplicates + "): already exist");
469: }
470: return null;
471: }
472: if (Debug.ON && getLogger() != null) {
473: logger.log(BasicLevel.DEBUG, "speedoAdd(, "
474: + allowDuplicates + "): adding");
475: }
476: // Put it in the "elements" list
477: GenClassElement element = (GenClassElement) createPIndexedElem();
478: element.setElement(o);
479: return (elements.add(element) ? element : null);
480: }
481: }
482:
483: protected GenClassElement speedoAddOnAttach(Object o,
484: boolean allowDuplicates) {
485: //TODO: implement the method
486: return speedoAdd(o, allowDuplicates);
487: }
488:
489: public boolean speedoRemove(Object o, Object hints) {
490: if (Debug.ON && getLogger() != null) {
491: logger.log(BasicLevel.DEBUG, "speedoRemove()");
492: }
493: return speedoRemove2(o) != null;
494: }
495:
496: public void forceDetachedDirty() {
497: }
498:
499: public void restoreDetachedNone() {
500: }
501:
502: }
|