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.io.IOException;
020: import java.io.ObjectInputStream;
021: import java.io.ObjectOutputStream;
022: import java.io.Serializable;
023: import java.math.BigDecimal;
024: import java.math.BigInteger;
025: import java.util.Date;
026:
027: import javax.jdo.PersistenceManager;
028:
029: import org.objectweb.jorm.api.PException;
030: import org.objectweb.jorm.api.PIndexedElem;
031: import org.objectweb.jorm.naming.api.PName;
032: import org.objectweb.jorm.naming.api.PNamingContext;
033: import org.objectweb.jorm.type.api.PExceptionTyping;
034: import org.objectweb.speedo.genclass.GenClassAccessor;
035: import org.objectweb.speedo.genclass.GenClassElement;
036: import org.objectweb.speedo.mim.api.StateItf;
037: import org.objectweb.speedo.mim.api.PersistentObjectItf;
038: import org.objectweb.speedo.pm.api.POManagerItf;
039: import org.objectweb.util.monolog.api.BasicLevel;
040: import org.objectweb.util.monolog.api.Logger;
041:
042: /**
043: * @author P. D?chamboux
044: */
045: public class CollectionElem implements PIndexedElem, GenClassElement {
046:
047: public final static boolean ELEMENT_IS_PNAME = true;
048:
049: /**
050: * The error message thrown when an accessor method associated to a
051: * primitive element type is called. Indeed this implementation supports
052: * only object elements.
053: */
054: public final static String ERROR_MESSAGE_BAD_FIELD_NAME = "Wrong index field name";
055:
056: /**
057: * The error message thrown when an accessor method associated to a
058: * primitive element type is called. Indeed this implementation supports
059: * only object elements.
060: */
061: public final static String ERROR_MESSAGE_NO_NULL_INDEX = "Null value not supported for index field";
062:
063: /**
064: * This constant is the name of the index field. This value must be use with
065: * the methods associated to the management of the index.
066: */
067: public final static String INDEX_FIELD_NAME = "idx";
068:
069: /**
070: * This field is the element (or its PName for a reference).
071: */
072: protected Object element;
073:
074: /**
075: * This field can be the index. The index type is known at instanciation
076: * time.
077: */
078: protected Object index;
079:
080: /**
081: * This field represents the satus of the PIndexedEleme. The possible value
082: * are ELEM_CREATED, ELEM_DELETED, ELEM_MODIFIED, ELEM_UNMODIFIED
083: */
084: protected byte status = ELEM_CREATED;
085:
086: protected GenClassAccessor gca;
087:
088: public CollectionElem(GenClassAccessor gca) {
089: this .gca = gca;
090: }
091:
092: public GenClassElement cloneGCE() {
093: return cloneGCE(new CollectionElem(gca));
094: }
095:
096: public GenClassElement cloneGCE(GenClassElement gce) {
097: ((CollectionElem) gce).status = status;
098: ((CollectionElem) gce).element = element;
099: ((CollectionElem) gce).index = index;
100: return gce;
101: }
102:
103: // IMPLEMENTATION OF THE GenClassElement INTERFACE //
104: // ------------------------------------------------//
105:
106: public Object getIndex() {
107: return index;
108: }
109:
110: public void setIndex(Object index) {
111: this .index = index;
112: }
113:
114: /**
115: * @return the element of the gen class. It is a user object.
116: */
117: public synchronized Object getElement() {
118: return getElement(null);
119: }
120:
121: /**
122: * Assignes the element of the gen class. It is a user object.
123: * @param element to add
124: */
125: public void setElement(Object element) {
126: this .element = element;
127: }
128:
129: /**
130: * @param pm is the persistence manager which permits to resolve the PName
131: * into a java reference.
132: * @return the element of the gen class. The element is a reference
133: * (PersistentObjectItf).
134: */
135: public Object getElement(POManagerItf pm) {
136: Object res = element;
137: if (res instanceof PName) {
138: synchronized (this ) {
139: if (res instanceof PName) {
140: POManagerItf mypm = pm;
141: if (mypm == null) {
142: mypm = ((PersistentObjectItf) gca.gcpo)
143: .speedoGetPOManager();
144: }
145: res = mypm.speedoGetObject((PName) res, false);
146: }
147: if (status != PIndexedElem.ELEM_DELETED) {
148: //when an element is deleted, it will be unbound from its
149: // identifier. Then all futur GenClassElement comparaison
150: // will be impossible if we do not have the identifier
151: element = res;
152: }
153: }
154: }
155: return res;
156: }
157:
158: public StateItf getSpeedoAccessor() {
159: return gca;
160: }
161:
162: public void unSwizzle() {
163: if (element instanceof PersistentObjectItf) {
164: synchronized (this ) {
165: if (element instanceof PersistentObjectItf) {
166: element = ((PersistentObjectItf) element)
167: .getPName();
168: }
169: }
170: }
171: }
172:
173: byte statusForMerge = PIndexedElem.ELEM_UNMODIFIED;
174:
175: public void cleanStatusForMerge() {
176: statusForMerge = PIndexedElem.ELEM_UNMODIFIED;
177: }
178:
179: public byte getStatusForMerge() {
180: return statusForMerge;
181: }
182:
183: public byte retainStatusForMerge() {
184: statusForMerge = status;
185: return statusForMerge;
186: }
187:
188: // IMPLEMENTATION OF THE Serializable INTERFACE //
189: // ---------------------------------------------//
190:
191: /**
192: * If the element is a PName, do not serialize it.
193: * Else, serialize it.
194: */
195: private void writeObject(ObjectOutputStream out) throws IOException {
196: if (!(element instanceof PName)) {
197: out.writeBoolean(!ELEMENT_IS_PNAME);
198: out.writeObject(element);
199: } else {
200: out.writeBoolean(ELEMENT_IS_PNAME);
201: }
202: out.writeObject(gca);
203: out.writeObject(index);
204: out.writeByte(status);
205: out.writeByte(statusForMerge);
206: }
207:
208: /**
209: * Symmetric method to de-serialize the object: test on if the element has been
210: * serialized or not.
211: */
212: private void readObject(ObjectInputStream in) throws IOException,
213: ClassNotFoundException {
214: //if the element attribute has been serialized, read it
215: if (in.readBoolean() != ELEMENT_IS_PNAME)
216: element = in.readObject();
217: else
218: element = null;
219: gca = (GenClassAccessor) in.readObject();
220: index = in.readObject();
221: status = in.readByte();
222: statusForMerge = in.readByte();
223: }
224:
225: // IMPLEMENTATION OF THE PIndexedElem INTERFACE //
226: // ---------------------------------------------//
227:
228: public byte getElemStatus() {
229: return status;
230: }
231:
232: public String pieGetStringElem() throws PExceptionTyping {
233: return (String) element;
234: }
235:
236: public Date pieGetDateElem() throws PExceptionTyping {
237: return (Date) element;
238: }
239:
240: public char[] pieGetCharArrayElem() throws PExceptionTyping {
241: return (char[]) element;
242: }
243:
244: public byte[] pieGetByteArrayElem() throws PExceptionTyping {
245: return (byte[]) element;
246: }
247:
248: public Serializable pieGetSerializedElem() throws PExceptionTyping {
249: return (Serializable) element;
250: }
251:
252: public PName pieGetRefElem() {
253: PName pn = (PName) (element instanceof PersistentObjectItf ? ((PersistentObjectItf) element)
254: .getPName()
255: : element);
256: try {
257: pn = ((PNamingContext) gca.getSpeedoPO().getPClassMapping()
258: .getPNameCoder()).export(null, pn);
259: } catch (Exception e) {
260: }
261: return pn;
262: }
263:
264: public boolean pieGetBooleanElem() throws PExceptionTyping {
265: return ((Boolean) element).booleanValue();
266: }
267:
268: public Boolean pieGetObooleanElem() throws PExceptionTyping {
269: return (Boolean) element;
270: }
271:
272: public byte pieGetByteElem() throws PExceptionTyping {
273: return ((Byte) element).byteValue();
274: }
275:
276: public Byte pieGetObyteElem() throws PExceptionTyping {
277: return (Byte) element;
278: }
279:
280: public char pieGetCharElem() throws PExceptionTyping {
281: return ((Character) element).charValue();
282: }
283:
284: public Character pieGetOcharElem() throws PExceptionTyping {
285: return (Character) element;
286: }
287:
288: public short pieGetShortElem() throws PExceptionTyping {
289: return ((Short) element).shortValue();
290: }
291:
292: public Short pieGetOshortElem() throws PExceptionTyping {
293: return (Short) element;
294: }
295:
296: public int pieGetIntElem() throws PExceptionTyping {
297: return ((Integer) element).intValue();
298: }
299:
300: public Integer pieGetOintElem() throws PExceptionTyping {
301: return (Integer) element;
302: }
303:
304: public long pieGetLongElem() throws PExceptionTyping {
305: return ((Long) element).longValue();
306: }
307:
308: public Long pieGetOlongElem() throws PExceptionTyping {
309: return (Long) element;
310: }
311:
312: public float pieGetFloatElem() throws PExceptionTyping {
313: return ((Float) element).floatValue();
314: }
315:
316: public Float pieGetOfloatElem() throws PExceptionTyping {
317: return (Float) element;
318: }
319:
320: public double pieGetDoubleElem() throws PExceptionTyping {
321: return ((Double) element).doubleValue();
322: }
323:
324: public Double pieGetOdoubleElem() throws PExceptionTyping {
325: return (Double) element;
326: }
327:
328: public BigDecimal pieGetBigDecimalElem() throws PException {
329: return (BigDecimal) element;
330: }
331:
332: public BigInteger pieGetBigIntegerElem() throws PException {
333: return (BigInteger) element;
334: }
335:
336: public void pieSetStringElem(String value) throws PExceptionTyping {
337: element = value;
338: }
339:
340: public void pieSetDateElem(Date value) throws PExceptionTyping {
341: element = value;
342: }
343:
344: public void pieSetCharArrayElem(char[] value)
345: throws PExceptionTyping {
346: element = value;
347: }
348:
349: public void pieSetByteArrayElem(byte[] value)
350: throws PExceptionTyping {
351: element = value;
352: }
353:
354: public void pieSetSerializedElem(Serializable value)
355: throws PExceptionTyping {
356: element = value;
357: }
358:
359: public void pieSetRefElem(PName value) throws PExceptionTyping {
360: element = value;
361: /*
362: try {
363: PersistenceManager pm = gca.speedoPO.jdoGetPersistenceManager();
364: JDOTransactionItf tx = (JDOTransactionItf) pm.currentTransaction();
365: element = value.resolve(tx.getConnectionHolder());
366: } catch (Exception e) {
367: ExceptionHelper.getNested(e).printStackTrace();
368: element = value;
369: }
370: */
371: }
372:
373: public void pieSetBooleanElem(boolean value)
374: throws PExceptionTyping {
375: element = Boolean.valueOf(value);
376: }
377:
378: public void pieSetObooleanElem(Boolean value)
379: throws PExceptionTyping {
380: element = value;
381: }
382:
383: public void pieSetByteElem(byte value) throws PExceptionTyping {
384: element = new Byte(value);
385: }
386:
387: public void pieSetObyteElem(Byte value) throws PExceptionTyping {
388: element = value;
389: }
390:
391: public void pieSetCharElem(char value) throws PExceptionTyping {
392: element = new Character(value);
393: }
394:
395: public void pieSetOcharElem(Character value)
396: throws PExceptionTyping {
397: element = value;
398: }
399:
400: public void pieSetShortElem(short value) throws PExceptionTyping {
401: element = new Short(value);
402: }
403:
404: public void pieSetOshortElem(Short value) throws PExceptionTyping {
405: element = value;
406: }
407:
408: public void pieSetIntElem(int value) throws PExceptionTyping {
409: element = new Integer(value);
410: }
411:
412: public void pieSetOintElem(Integer value) throws PExceptionTyping {
413: element = value;
414: }
415:
416: public void pieSetLongElem(long value) throws PExceptionTyping {
417: element = new Long(value);
418: }
419:
420: public void pieSetOlongElem(Long value) throws PExceptionTyping {
421: element = value;
422: }
423:
424: public void pieSetFloatElem(float value) throws PExceptionTyping {
425: element = new Float(value);
426: }
427:
428: public void pieSetOfloatElem(Float value) throws PExceptionTyping {
429: element = value;
430: }
431:
432: public void pieSetDoubleElem(double value) throws PExceptionTyping {
433: element = new Double(value);
434: }
435:
436: public void pieSetOdoubleElem(Double value) throws PExceptionTyping {
437: element = value;
438: }
439:
440: public void pieSetBigDecimalElem(BigDecimal bigDecimal)
441: throws PException {
442: element = bigDecimal;
443: }
444:
445: public void pieSetBigIntegerElem(BigInteger value)
446: throws PException {
447: element = value;
448: }
449:
450: // ---------------------------------------------------------------------------
451: // Index accessor
452: // ---------------------------------------------------------------------------
453:
454: public void pieSetByteIndexField(String fn, byte value)
455: throws PExceptionTyping {
456: if (!INDEX_FIELD_NAME.equals(fn))
457: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
458: index = new Byte(value);
459: }
460:
461: public void pieSetObyteIndexField(String fn, Byte value)
462: throws PExceptionTyping {
463: if (!INDEX_FIELD_NAME.equals(fn))
464: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
465: if (value == null)
466: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
467: index = value;
468: }
469:
470: public void pieSetCharIndexField(String fn, char value)
471: throws PExceptionTyping {
472: if (!INDEX_FIELD_NAME.equals(fn))
473: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
474: index = new Character(value);
475: }
476:
477: public void pieSetOcharIndexField(String fn, Character value)
478: throws PExceptionTyping {
479: if (!INDEX_FIELD_NAME.equals(fn))
480: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
481: if (value == null)
482: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
483: index = value;
484: }
485:
486: public void pieSetShortIndexField(String fn, short value)
487: throws PExceptionTyping {
488: if (!INDEX_FIELD_NAME.equals(fn))
489: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
490: index = new Short(value);
491: }
492:
493: public void pieSetOshortIndexField(String fn, Short value)
494: throws PExceptionTyping {
495: if (!INDEX_FIELD_NAME.equals(fn))
496: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
497: if (value == null)
498: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
499: index = value;
500: }
501:
502: public void pieSetIntIndexField(String fn, int value)
503: throws PExceptionTyping {
504: if (!INDEX_FIELD_NAME.equals(fn))
505: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
506: index = new Integer(value);
507: }
508:
509: public void pieSetOintIndexField(String fn, Integer value)
510: throws PExceptionTyping {
511: if (!INDEX_FIELD_NAME.equals(fn))
512: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
513: if (value == null)
514: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
515: index = value;
516: }
517:
518: public void pieSetLongIndexField(String fn, long value)
519: throws PExceptionTyping {
520: if (!INDEX_FIELD_NAME.equals(fn))
521: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
522: index = new Long(value);
523: }
524:
525: public void pieSetOlongIndexField(String fn, Long value)
526: throws PExceptionTyping {
527: if (!INDEX_FIELD_NAME.equals(fn))
528: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
529: if (value == null)
530: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
531: index = value;
532: }
533:
534: public void pieSetStringIndexField(String fn, String value)
535: throws PExceptionTyping {
536: if (!INDEX_FIELD_NAME.equals(fn))
537: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
538: if (value == null)
539: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
540: index = value;
541: }
542:
543: public void pieSetDateIndexField(String fn, Date value)
544: throws PExceptionTyping {
545: if (!INDEX_FIELD_NAME.equals(fn))
546: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
547: if (value == null)
548: throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
549: index = value;
550: }
551:
552: public short pieGetShortIndexField(String fn)
553: throws PExceptionTyping {
554: if (!INDEX_FIELD_NAME.equals(fn))
555: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
556: return ((Short) index).shortValue();
557: }
558:
559: public Short pieGetOshortIndexField(String fn)
560: throws PExceptionTyping {
561: if (!INDEX_FIELD_NAME.equals(fn))
562: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
563: return (Short) index;
564: }
565:
566: public long pieGetLongIndexField(String fn) throws PExceptionTyping {
567: if (!INDEX_FIELD_NAME.equals(fn))
568: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
569: return ((Long) index).longValue();
570: }
571:
572: public Long pieGetOlongIndexField(String fn)
573: throws PExceptionTyping {
574: if (!INDEX_FIELD_NAME.equals(fn))
575: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
576: return (Long) index;
577: }
578:
579: public int pieGetIntIndexField(String fn) throws PExceptionTyping {
580: if (!INDEX_FIELD_NAME.equals(fn))
581: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
582: return ((Integer) index).intValue();
583: }
584:
585: public Integer pieGetOintIndexField(String fn)
586: throws PExceptionTyping {
587: if (!INDEX_FIELD_NAME.equals(fn))
588: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
589: return (Integer) index;
590: }
591:
592: public String pieGetStringIndexField(String fn)
593: throws PExceptionTyping {
594: if (!INDEX_FIELD_NAME.equals(fn))
595: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
596: return (String) index;
597: }
598:
599: public Date pieGetDateIndexField(String fn) throws PExceptionTyping {
600: if (!INDEX_FIELD_NAME.equals(fn))
601: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
602: return (Date) index;
603: }
604:
605: public byte pieGetByteIndexField(String fn) throws PExceptionTyping {
606: if (!INDEX_FIELD_NAME.equals(fn))
607: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
608: return ((Byte) index).byteValue();
609: }
610:
611: public Byte pieGetObyteIndexField(String fn)
612: throws PExceptionTyping {
613: if (!INDEX_FIELD_NAME.equals(fn))
614: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
615: return (Byte) index;
616: }
617:
618: public char pieGetCharIndexField(String fn) throws PExceptionTyping {
619: if (!INDEX_FIELD_NAME.equals(fn))
620: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
621: return ((Character) index).charValue();
622: }
623:
624: public Character pieGetOcharIndexField(String fn)
625: throws PExceptionTyping {
626: if (!INDEX_FIELD_NAME.equals(fn))
627: throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
628: return (Character) index;
629: }
630:
631: // ---------------------------------------------------------------------------
632: // Other methods
633: // ---------------------------------------------------------------------------
634:
635: public void setStatus(byte s) {
636: status = s;
637: if (status == PIndexedElem.ELEM_DELETED) {
638: //One of the reason to remove an element from the collection, is
639: //that the element is deleted. So when the element is deleted, it
640: // is not no more bound to a PName. Then here we decide to fetch the
641: // PName in advance but when it is possible.
642: unSwizzle();
643: }
644: }
645:
646: public boolean equals(Object o) {
647: if (!(o instanceof CollectionElem)) {
648: return false;
649: }
650: Object objIndex = ((CollectionElem) o).getIndex();
651: if ((index == null && objIndex != null)
652: || (index != null && !index.equals(objIndex))) {
653: return false;
654: }
655: //Store the element value in a local variable in order to avoid
656: // syncrhonization
657: Object objElement = element;
658: //Fetch the real element without causing the loading of the persistent
659: //instance: do not use the getElement() methods, but direct access to
660: // the field.
661: Object ceElem = ((CollectionElem) o).element;
662: if (objElement == null) {
663: return ceElem == null;
664: }
665: if (ceElem == null) {
666: return false;
667: }
668: if (objElement instanceof PName) {
669: if (ceElem instanceof PName) {
670: return objElement.equals(ceElem);
671: } else if (ceElem instanceof PersistentObjectItf) {
672: return objElement.equals(((PersistentObjectItf) ceElem)
673: .getPName());
674: } else {
675: return false;
676: }
677: } else if (objElement instanceof PersistentObjectItf) {
678: if (ceElem instanceof PName) {
679: Object pn = ((PersistentObjectItf) objElement)
680: .getPName();
681: if (pn == null) {
682: Logger l = gca.getLogger();
683: if (l != null) {
684: l
685: .log(
686: BasicLevel.WARN,
687: "Internal error: a collection/set/map elemnent is no more persistent and it is impossible to compare it: ",
688: new RuntimeException());
689: }
690: return false;
691: } else {
692: return pn.equals(ceElem);
693: }
694: } else if (ceElem instanceof PersistentObjectItf) {
695: return objElement == ceElem;
696: } else {
697: return false;
698: }
699: } else {
700: return objElement.equals(ceElem);
701: }
702: }
703: }
|