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.map;
018:
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.Collections;
022: import java.util.HashMap;
023: import java.util.HashSet;
024: import java.util.Iterator;
025: import java.util.Map;
026: import java.util.Set;
027:
028: import org.objectweb.jorm.api.PExceptionIO;
029: import org.objectweb.jorm.api.PIndexedElem;
030: import org.objectweb.jorm.naming.api.PName;
031: import org.objectweb.speedo.api.Debug;
032: import org.objectweb.speedo.genclass.GenClassAccessor;
033: import org.objectweb.speedo.genclass.GenClassElement;
034: import org.objectweb.speedo.genclass.AbstractGenClassHome;
035: import org.objectweb.speedo.genclass.api.SpeedoGenClassPO;
036: import org.objectweb.speedo.metadata.SpeedoFetchGroup;
037: import org.objectweb.speedo.mim.api.DetachedLifeCycle;
038: import org.objectweb.speedo.mim.api.LifeCycle;
039: import org.objectweb.speedo.mim.api.StateItf;
040: import org.objectweb.speedo.mim.api.PersistentObjectItf;
041: import org.objectweb.speedo.pm.api.POManagerItf;
042: import org.objectweb.util.monolog.api.BasicLevel;
043:
044: public class MapAccessor extends GenClassAccessor implements Map {
045:
046: /**
047: * A map containing the indexed elements of the genclass. It associates each
048: * element to its index. This map does NOT contain the deleted elements.
049: */
050: protected Map map = null;
051:
052: /**
053: * Instanciates and initializes a new map with an initial size.
054: */
055: public MapAccessor(SpeedoGenClassPO apo) {
056: super (apo);
057: this .elements = new ArrayList();
058: this .map = (Map) gcpo.createGenClass();
059: }
060:
061: public void makePersistent(POManagerItf pm) {
062: if (Debug.ON && getLogger() != null) {
063: logger.log(BasicLevel.DEBUG, "makePersistent");
064: }
065: if (elements.size() > 0) {
066: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
067: .makePersistent(pm, values().iterator(), null, null);
068: }
069: }
070:
071: public void deletePersistent(POManagerItf pm) {
072: clear();
073: }
074:
075: public void setElements(Object o) {
076: clear();
077: if (o != null) {
078: putAll(((Map) o));
079: }
080: }
081:
082: public void loadFieldsFromAccessor(StateItf sa) {
083: MapAccessor ma = (MapAccessor) sa;
084: map.clear();
085: map.putAll(ma.map);
086: supportDelta = ma.supportDelta;
087: elements.clear();
088: elements.addAll(ma.elements);
089: speedoSetStatus(ma.speedoGetStatus());
090: }
091:
092: public boolean speedoAdd(Object elemToAdd, Object hints) {
093: put(hints, elemToAdd, false);
094: return true;
095: }
096:
097: public boolean speedoRemove(Object elemToRemove, Object hints) {
098: return remove(hints, false) != null;
099: }
100:
101: public void detachCopy(POManagerItf pm, Map detachCtx,
102: StateItf fieldsClone, Collection fgHints) {
103: ((MapAccessor) fieldsClone).map = new HashMap();
104: ((MapAccessor) fieldsClone).loadFieldsFromAccessor(this );
105: //copy the elements in the map: collection is no more available when the po is not active
106: ((MapAccessor) fieldsClone).map.clear();
107: boolean valueToFetch = false;
108: Collection fgHintsToSend = new ArrayList();
109: synchronized (fgHints) {
110: Collection copyFgHints = new ArrayList(fgHints);
111: Iterator it2 = copyFgHints.iterator();
112: while (it2.hasNext() && !valueToFetch) {
113: String s = (String) it2.next();
114: int idxValue = s.indexOf(SpeedoFetchGroup.FG_VALUE);
115: if (s.indexOf(SpeedoFetchGroup.FG_KEY) != -1)
116: fgHints.remove(s);
117: else if (idxValue != -1) {
118: valueToFetch = true;
119: fgHints.remove(s);
120: String add = s.substring(idxValue
121: + SpeedoFetchGroup.FG_VALUE.length());
122: if (add.length() > 0) {
123: fgHintsToSend.add(add);
124: }
125: }
126: }
127: }
128: //get an interator on the PIndexed elements
129: Iterator it = ((GenClassAccessor) fieldsClone).elements
130: .iterator();
131: while (it.hasNext()) {
132: //get the PIndexElement
133: MapElem iElem = (MapElem) it.next();
134: Object elem = iElem.getElement(pm);
135: Object clone = null;
136: //if the element is a Persistent Object
137: if (elem instanceof PersistentObjectItf) {
138: //get the speedo po associated
139: PersistentObjectItf sp = (PersistentObjectItf) elem;
140: if (detachCtx != null)
141: clone = detachCtx.get(sp);
142: if (clone == null) {
143: synchronized (fgHints) {
144: if (valueToFetch) {
145: // get the clone of the speedo po
146: clone = pm.speedoDetachCopy(sp, detachCtx,
147: fgHintsToSend);
148: }
149: }
150: }
151: } else {
152: //just copy the java object
153: clone = elem;
154: }
155: Object key = iElem.getIndex();
156: //add it in the map of elements reachable when the po is no more active
157: ((MapAccessor) fieldsClone).map.put(key, clone);
158: }
159: ((GenClassAccessor) fieldsClone)
160: .speedoSetStatus(LifeCycle.TRANSIENT);
161: }
162:
163: public void attachCopy(POManagerItf pm, Map attachCtx,
164: StateItf fieldsClone) {
165: MapAccessor ma = (MapAccessor) fieldsClone;
166: //get an iterator on the PIndexed elements of the collection
167: Iterator it = ma.map.entrySet().iterator();
168: while (it.hasNext()) {
169: Map.Entry mapEntry = (Map.Entry) it.next();
170: Object elem = mapEntry.getValue();
171: Object key = mapEntry.getKey();
172: boolean put = true;
173: if (elem instanceof MapElem) {
174: //if the element has not been touched, do not put it in the map again
175: put = false;
176: elem = ((MapElem) elem).getElement();
177: }
178: //if the element is a Persistent Object, attach it
179: if (elem instanceof PersistentObjectItf) {
180: //get the detached speedo po
181: PersistentObjectItf spDetached = (PersistentObjectItf) elem;
182: PersistentObjectItf sp = (PersistentObjectItf) attachCtx
183: .get(spDetached);
184: if (sp == null) {
185: attachCtx.put(spDetached, sp);
186: sp = (PersistentObjectItf) pm.speedoAttachCopy(
187: spDetached, attachCtx);
188: }
189: //get the pname
190: elem = sp.getPName();
191: }
192: if (put) {
193: //put the elem in the element list
194: put(key, elem, false);
195: }
196: }
197: }
198:
199: public void refresh(POManagerItf pm, Map refreshCtx,
200: Collection fgHints) {
201: commonRefreshRetrieve(pm, refreshCtx, fgHints, true);
202: }
203:
204: public void retrieve(POManagerItf pm, Map retrieveCtx,
205: Collection fgHints) {
206: commonRefreshRetrieve(pm, retrieveCtx, fgHints, false);
207: }
208:
209: /**
210: *
211: * @param pm
212: * @param ctx
213: * @param fgHints
214: * @param refresh: if true, call refresh, else call retrieve
215: */
216: //TODO: what about refreshing a map of String, Double, Integer???
217: private void commonRefreshRetrieve(POManagerItf pm, Map ctx,
218: Collection fgHints, boolean refresh) {
219: boolean valueToFetch = false;
220: Collection fgHintsToSend = new ArrayList();
221: synchronized (fgHints) {
222: Collection copyFgHints = new ArrayList(fgHints);
223: Iterator it2 = copyFgHints.iterator();
224: while (it2.hasNext() && !valueToFetch) {
225: String s = (String) it2.next();
226: int idxValue = s.indexOf(SpeedoFetchGroup.FG_VALUE);
227: if (s.indexOf(SpeedoFetchGroup.FG_KEY) != -1)
228: fgHints.remove(s);
229: else if (idxValue != -1) {
230: valueToFetch = true;
231: fgHints.remove(s);
232: String add = s.substring(idxValue
233: + SpeedoFetchGroup.FG_VALUE.length());
234: if (add.length() > 0) {
235: fgHintsToSend.add(add);
236: }
237: }
238: }
239: }
240: //get an interator on the PIndexed elements
241: Iterator it = this .elements.iterator();
242: while (it.hasNext()) {
243: //get the PIndexElement
244: MapElem iElem = (MapElem) it.next();
245: Object elem = iElem.getElement(pm);
246: //if the element is a PO
247: if (elem instanceof PersistentObjectItf) {
248: //get the speedo po associated
249: PersistentObjectItf sp = (PersistentObjectItf) elem;
250: if (ctx != null && !ctx.containsKey(sp.getPName())) {
251: synchronized (fgHints) {
252: if (valueToFetch) {
253: if (refresh) {
254: //refresh
255: pm
256: .speedoRefresh(sp, ctx,
257: fgHintsToSend);
258: } else {
259: //retrieve
260: pm.speedoRetrieve(sp, ctx,
261: fgHintsToSend);
262: }
263: }
264: }
265: }
266: }
267: }
268: }
269:
270: public Object put(Object key, Object value, boolean withCoherence) {
271: MapElem element = null;
272: Object res = map.get(key);
273: //if detached, just put the value in the map
274: if (detachedStatus != DetachedLifeCycle.DETACHED_NONE) {
275: map.put(key, value);
276: } else {
277: if (res == null) {
278: // Put a new entry in the map
279: element = (MapElem) createPIndexedElem();
280: element.setIndex(key);
281: elements.add(element);
282: map.put(key, element);
283: } else {
284: // Mark as modify
285: element = (MapElem) res;
286: element.setStatus(PIndexedElem.ELEM_MODIFIED);
287: res = element.getElement(gcpo.speedoGetPOManager());
288: }
289: element.setElement(value);
290:
291: if (value instanceof PersistentObjectItf) {
292: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
293: .makePersistent(null,
294: (PersistentObjectItf) value,
295: (SpeedoGenClassPO) getSpeedoPO(), null);
296: }
297: }
298:
299: if (withCoherence) {
300: Object v = value;
301: if (v instanceof PName) {
302: v = element.getElement(gcpo.speedoGetPOManager());
303: }
304: if (v instanceof PersistentObjectItf) {
305: gcpo.fireSpeedoElementAdded(v);
306: }
307: }
308: return res;
309: }
310:
311: public Object remove(Object key, boolean withCoherence) {
312: //if detached, just remove the key entry from the map, it returns the value
313: if (detachedStatus != DetachedLifeCycle.DETACHED_NONE) {
314: return map.remove(key);
315: } else {
316: GenClassElement gcelem = (GenClassElement) map.get(key);
317: if (gcelem == null) {
318: return null;
319: }
320: gcelem.setStatus(PIndexedElem.ELEM_DELETED);
321: Object value = get(key);
322: map.remove(key);
323: if (withCoherence) {
324: Object el = gcelem
325: .getElement(gcpo.speedoGetPOManager());
326: if (el != null) {
327: gcpo.fireSpeedoElementRemoved(el);
328: }
329: }
330: return value;
331: }
332: }
333:
334: // ------------------------------------------------------------------------
335: // IMPLEMENTATION OF THE Map INTERFACE
336: // ------------------------------------------------------------------------
337:
338: public int size() {
339: return map.size();
340: }
341:
342: public boolean isEmpty() {
343: return map.isEmpty();
344: }
345:
346: public boolean containsKey(Object key) {
347: return map.containsKey(key);
348: }
349:
350: public boolean containsValue(Object value) {
351: // TODO: support the containsValue method on Map
352: return false;
353: }
354:
355: public Object get(Object key) {
356: Object value = map.get(key);
357: if (value == null) {
358: return null;
359: } else {
360: //if the state is detached
361: if (detachedStatus != DetachedLifeCycle.DETACHED_NONE)
362: return value;
363: else
364: return ((MapElem) value).getElement(gcpo
365: .speedoGetPOManager());
366: }
367: }
368:
369: public Object put(Object key, Object value) {
370: return put(key, value, true);
371: }
372:
373: public Object remove(Object key) {
374: return remove(key, true);
375: }
376:
377: public void putAll(Map t) {
378: Iterator i = t.entrySet().iterator();
379: while (i.hasNext()) {
380: Map.Entry entry = (Map.Entry) i.next();
381: put(entry.getKey(), entry.getValue());
382: }
383: }
384:
385: public void clear() {
386: if (detachedStatus == DetachedLifeCycle.DETACHED_NONE) {
387: Iterator i = elements.iterator();
388: POManagerItf pm = null;
389: while (i.hasNext()) {
390: GenClassElement gcelem = (GenClassElement) i.next();
391: gcelem.setStatus(PIndexedElem.ELEM_DELETED);
392: if (pm == null) {
393: pm = gcpo.speedoGetPOManager();
394: }
395: Object el = gcelem.getElement(pm);
396: if (el != null) {
397: gcpo.fireSpeedoElementRemoved(el);
398: }
399: }
400: }
401: map.clear();
402: supportDelta = false;
403: }
404:
405: public Set keySet() {
406: return Collections.unmodifiableSet(map.keySet());
407: }
408:
409: public Collection values() {
410: ArrayList res = new ArrayList(elements.size());
411: //if detached, look into map
412: if (detachedStatus != DetachedLifeCycle.DETACHED_NONE) {
413: Iterator it = map.values().iterator();
414: while (it.hasNext()) {
415: res.add(it.next());
416: }
417: } else {
418: //else, look into elements
419: for (int i = (elements.size() - 1); i >= 0; i--) {
420: MapElem me = (MapElem) elements.get(i);
421: if (me.getElemStatus() != PIndexedElem.ELEM_DELETED) {
422: res.add(me.getElement());
423: }
424: }
425: }
426: return Collections.unmodifiableCollection(res);
427: }
428:
429: public Set entrySet() {
430: if (detachedStatus != DetachedLifeCycle.DETACHED_NONE) {
431: return map.entrySet();
432: } else {
433: Set res = new HashSet(elements.size());
434: for (int i = (elements.size() - 1); i >= 0; i--) {
435: MapElem me = (MapElem) elements.get(i);
436: if (me.getElemStatus() != PIndexedElem.ELEM_DELETED) {
437: res.add(new MyMapEntry(me));
438: }
439: }
440: return Collections.unmodifiableSet(res);
441: }
442: }
443:
444: private class MyMapEntry implements Map.Entry {
445: MapElem me;
446:
447: public MyMapEntry(MapElem _me) {
448: this .me = _me;
449: }
450:
451: public Object getKey() {
452: return me.getIndex();
453: }
454:
455: public Object getValue() {
456: return me.getElement();
457: }
458:
459: public Object setValue(Object value) {
460: Object res = me.getElement();
461: me.setStatus(PIndexedElem.ELEM_MODIFIED);
462: me.setElement(value);
463: return res;
464: }
465: }
466:
467: // ------------------------------------------------------------------------
468: // IMPLEMENTATION OF THE PGenClassAccessor INTERFACE
469: // ------------------------------------------------------------------------
470: public PIndexedElem createPIndexedElem(GenClassAccessor gca) {
471: return new MapElem(gca);
472: }
473:
474: public void paAdd(PIndexedElem elem, Object conn)
475: throws PExceptionIO {
476: GenClassElement gcelem = (GenClassElement) elem;
477: // the elem is read from the DS, set it to unmodified.
478: gcelem.setStatus(PIndexedElem.ELEM_UNMODIFIED);
479: elements.add(gcelem);
480: map.put(gcelem.getIndex(), gcelem);
481: }
482:
483: public int paGetNbElem() {
484: return size();
485: }
486:
487: public Iterator paIterator() {
488: return elements.iterator();
489: }
490:
491: public void paSetNbElem(int nbelem) {
492: if (nbelem == -1) {
493: elements = new ArrayList();
494: } else {
495: elements = new ArrayList(nbelem);
496: }
497: map = (Map) gcpo.createGenClass();
498: }
499:
500: public void forceDetachedDirty() {
501: }
502:
503: public void restoreDetachedNone() {
504: }
505:
506: public void makePersistentOnAttach(POManagerItf pm, Map map) {
507: if (Debug.ON && getLogger() != null) {
508: logger.log(BasicLevel.DEBUG, "makePersistent");
509: }
510: if (elements.size() > 0) {
511: ((AbstractGenClassHome) getSpeedoPO().speedoGetHome())
512: .makePersistent(pm, values().iterator(), null, map);
513: }
514: }
515:
516: }
|