/**
* Copyright (C) 2001-2004 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package org.objectweb.speedo.genclass.collection;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Date;
import javax.jdo.PersistenceManager;
import org.objectweb.jorm.api.PException;
import org.objectweb.jorm.api.PIndexedElem;
import org.objectweb.jorm.naming.api.PName;
import org.objectweb.jorm.naming.api.PNamingContext;
import org.objectweb.jorm.type.api.PExceptionTyping;
import org.objectweb.speedo.genclass.GenClassAccessor;
import org.objectweb.speedo.genclass.GenClassElement;
import org.objectweb.speedo.mim.api.StateItf;
import org.objectweb.speedo.mim.api.PersistentObjectItf;
import org.objectweb.speedo.pm.api.POManagerItf;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
/**
* @author P. D?chamboux
*/
public class CollectionElem implements PIndexedElem, GenClassElement {
public final static boolean ELEMENT_IS_PNAME = true;
/**
* The error message thrown when an accessor method associated to a
* primitive element type is called. Indeed this implementation supports
* only object elements.
*/
public final static String ERROR_MESSAGE_BAD_FIELD_NAME =
"Wrong index field name";
/**
* The error message thrown when an accessor method associated to a
* primitive element type is called. Indeed this implementation supports
* only object elements.
*/
public final static String ERROR_MESSAGE_NO_NULL_INDEX =
"Null value not supported for index field";
/**
* This constant is the name of the index field. This value must be use with
* the methods associated to the management of the index.
*/
public final static String INDEX_FIELD_NAME = "idx";
/**
* This field is the element (or its PName for a reference).
*/
protected Object element;
/**
* This field can be the index. The index type is known at instanciation
* time.
*/
protected Object index;
/**
* This field represents the satus of the PIndexedEleme. The possible value
* are ELEM_CREATED, ELEM_DELETED, ELEM_MODIFIED, ELEM_UNMODIFIED
*/
protected byte status = ELEM_CREATED;
protected GenClassAccessor gca;
public CollectionElem(GenClassAccessor gca) {
this.gca = gca;
}
public GenClassElement cloneGCE() {
return cloneGCE(new CollectionElem(gca));
}
public GenClassElement cloneGCE(GenClassElement gce) {
((CollectionElem) gce).status = status;
((CollectionElem) gce).element = element;
((CollectionElem) gce).index = index;
return gce;
}
// IMPLEMENTATION OF THE GenClassElement INTERFACE //
// ------------------------------------------------//
public Object getIndex() {
return index;
}
public void setIndex(Object index) {
this.index = index;
}
/**
* @return the element of the gen class. It is a user object.
*/
public synchronized Object getElement() {
return getElement(null);
}
/**
* Assignes the element of the gen class. It is a user object.
* @param element to add
*/
public void setElement(Object element) {
this.element = element;
}
/**
* @param pm is the persistence manager which permits to resolve the PName
* into a java reference.
* @return the element of the gen class. The element is a reference
* (PersistentObjectItf).
*/
public Object getElement(POManagerItf pm) {
Object res = element;
if (res instanceof PName) {
synchronized(this) {
if (res instanceof PName) {
POManagerItf mypm = pm;
if (mypm == null) {
mypm = ((PersistentObjectItf) gca.gcpo).speedoGetPOManager();
}
res = mypm.speedoGetObject((PName) res, false);
}
if (status != PIndexedElem.ELEM_DELETED) {
//when an element is deleted, it will be unbound from its
// identifier. Then all futur GenClassElement comparaison
// will be impossible if we do not have the identifier
element = res;
}
}
}
return res;
}
public StateItf getSpeedoAccessor() {
return gca;
}
public void unSwizzle() {
if (element instanceof PersistentObjectItf) {
synchronized(this) {
if (element instanceof PersistentObjectItf) {
element = ((PersistentObjectItf) element).getPName();
}
}
}
}
byte statusForMerge = PIndexedElem.ELEM_UNMODIFIED;
public void cleanStatusForMerge() {
statusForMerge = PIndexedElem.ELEM_UNMODIFIED;
}
public byte getStatusForMerge() {
return statusForMerge;
}
public byte retainStatusForMerge() {
statusForMerge = status;
return statusForMerge;
}
// IMPLEMENTATION OF THE Serializable INTERFACE //
// ---------------------------------------------//
/**
* If the element is a PName, do not serialize it.
* Else, serialize it.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
if (!(element instanceof PName)) {
out.writeBoolean(!ELEMENT_IS_PNAME);
out.writeObject(element);
} else {
out.writeBoolean(ELEMENT_IS_PNAME);
}
out.writeObject(gca);
out.writeObject(index);
out.writeByte(status);
out.writeByte(statusForMerge);
}
/**
* Symmetric method to de-serialize the object: test on if the element has been
* serialized or not.
*/
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//if the element attribute has been serialized, read it
if (in.readBoolean() != ELEMENT_IS_PNAME)
element = in.readObject();
else
element = null;
gca = (GenClassAccessor) in.readObject();
index = in.readObject();
status = in.readByte();
statusForMerge = in.readByte();
}
// IMPLEMENTATION OF THE PIndexedElem INTERFACE //
// ---------------------------------------------//
public byte getElemStatus() {
return status;
}
public String pieGetStringElem() throws PExceptionTyping {
return (String) element;
}
public Date pieGetDateElem() throws PExceptionTyping {
return (Date) element;
}
public char[] pieGetCharArrayElem() throws PExceptionTyping {
return (char[]) element;
}
public byte[] pieGetByteArrayElem() throws PExceptionTyping {
return (byte[]) element;
}
public Serializable pieGetSerializedElem() throws PExceptionTyping {
return (Serializable) element;
}
public PName pieGetRefElem() {
PName pn = (PName) (element instanceof PersistentObjectItf
? ((PersistentObjectItf) element).getPName()
: element);
try {
pn = ((PNamingContext) gca.getSpeedoPO().getPClassMapping()
.getPNameCoder()).export(null, pn);
} catch (Exception e) {
}
return pn;
}
public boolean pieGetBooleanElem() throws PExceptionTyping {
return ((Boolean) element).booleanValue();
}
public Boolean pieGetObooleanElem() throws PExceptionTyping {
return (Boolean) element;
}
public byte pieGetByteElem() throws PExceptionTyping {
return ((Byte) element).byteValue();
}
public Byte pieGetObyteElem() throws PExceptionTyping {
return (Byte) element;
}
public char pieGetCharElem() throws PExceptionTyping {
return ((Character) element).charValue();
}
public Character pieGetOcharElem() throws PExceptionTyping {
return (Character) element;
}
public short pieGetShortElem() throws PExceptionTyping {
return ((Short) element).shortValue();
}
public Short pieGetOshortElem() throws PExceptionTyping {
return (Short) element;
}
public int pieGetIntElem() throws PExceptionTyping {
return ((Integer) element).intValue();
}
public Integer pieGetOintElem() throws PExceptionTyping {
return (Integer) element;
}
public long pieGetLongElem() throws PExceptionTyping {
return ((Long) element).longValue();
}
public Long pieGetOlongElem() throws PExceptionTyping {
return (Long) element;
}
public float pieGetFloatElem() throws PExceptionTyping {
return ((Float) element).floatValue();
}
public Float pieGetOfloatElem() throws PExceptionTyping {
return (Float) element;
}
public double pieGetDoubleElem() throws PExceptionTyping {
return ((Double) element).doubleValue();
}
public Double pieGetOdoubleElem() throws PExceptionTyping {
return (Double) element;
}
public BigDecimal pieGetBigDecimalElem() throws PException {
return (BigDecimal) element;
}
public BigInteger pieGetBigIntegerElem() throws PException {
return (BigInteger) element;
}
public void pieSetStringElem(String value) throws PExceptionTyping {
element = value;
}
public void pieSetDateElem(Date value) throws PExceptionTyping {
element = value;
}
public void pieSetCharArrayElem(char[] value) throws PExceptionTyping {
element = value;
}
public void pieSetByteArrayElem(byte[] value) throws PExceptionTyping {
element = value;
}
public void pieSetSerializedElem(Serializable value) throws PExceptionTyping {
element = value;
}
public void pieSetRefElem(PName value) throws PExceptionTyping {
element = value;
/*
try {
PersistenceManager pm = gca.speedoPO.jdoGetPersistenceManager();
JDOTransactionItf tx = (JDOTransactionItf) pm.currentTransaction();
element = value.resolve(tx.getConnectionHolder());
} catch (Exception e) {
ExceptionHelper.getNested(e).printStackTrace();
element = value;
}
*/
}
public void pieSetBooleanElem(boolean value) throws PExceptionTyping {
element = Boolean.valueOf(value);
}
public void pieSetObooleanElem(Boolean value) throws PExceptionTyping {
element = value;
}
public void pieSetByteElem(byte value) throws PExceptionTyping {
element = new Byte(value);
}
public void pieSetObyteElem(Byte value) throws PExceptionTyping {
element = value;
}
public void pieSetCharElem(char value) throws PExceptionTyping {
element = new Character(value);
}
public void pieSetOcharElem(Character value) throws PExceptionTyping {
element = value;
}
public void pieSetShortElem(short value) throws PExceptionTyping {
element = new Short(value);
}
public void pieSetOshortElem(Short value) throws PExceptionTyping {
element = value;
}
public void pieSetIntElem(int value) throws PExceptionTyping {
element = new Integer(value);
}
public void pieSetOintElem(Integer value) throws PExceptionTyping {
element = value;
}
public void pieSetLongElem(long value) throws PExceptionTyping {
element = new Long(value);
}
public void pieSetOlongElem(Long value) throws PExceptionTyping {
element = value;
}
public void pieSetFloatElem(float value) throws PExceptionTyping {
element = new Float(value);
}
public void pieSetOfloatElem(Float value) throws PExceptionTyping {
element = value;
}
public void pieSetDoubleElem(double value) throws PExceptionTyping {
element = new Double(value);
}
public void pieSetOdoubleElem(Double value) throws PExceptionTyping {
element = value;
}
public void pieSetBigDecimalElem(BigDecimal bigDecimal) throws PException {
element = bigDecimal;
}
public void pieSetBigIntegerElem(BigInteger value) throws PException {
element = value;
}
// ---------------------------------------------------------------------------
// Index accessor
// ---------------------------------------------------------------------------
public void pieSetByteIndexField(String fn, byte value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
index = new Byte(value);
}
public void pieSetObyteIndexField(String fn, Byte value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetCharIndexField(String fn, char value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
index = new Character(value);
}
public void pieSetOcharIndexField(String fn, Character value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetShortIndexField(String fn, short value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
index = new Short(value);
}
public void pieSetOshortIndexField(String fn, Short value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetIntIndexField(String fn, int value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
index = new Integer(value);
}
public void pieSetOintIndexField(String fn, Integer value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetLongIndexField(String fn, long value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
index = new Long(value);
}
public void pieSetOlongIndexField(String fn, Long value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetStringIndexField(String fn, String value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public void pieSetDateIndexField(String fn, Date value) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
if (value == null)
throw new PExceptionTyping(ERROR_MESSAGE_NO_NULL_INDEX);
index = value;
}
public short pieGetShortIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return ((Short) index).shortValue();
}
public Short pieGetOshortIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Short) index;
}
public long pieGetLongIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return ((Long) index).longValue();
}
public Long pieGetOlongIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Long) index;
}
public int pieGetIntIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return ((Integer) index).intValue();
}
public Integer pieGetOintIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Integer) index;
}
public String pieGetStringIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (String) index;
}
public Date pieGetDateIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Date) index;
}
public byte pieGetByteIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return ((Byte) index).byteValue();
}
public Byte pieGetObyteIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Byte) index;
}
public char pieGetCharIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return ((Character) index).charValue();
}
public Character pieGetOcharIndexField(String fn) throws PExceptionTyping {
if (!INDEX_FIELD_NAME.equals(fn))
throw new PExceptionTyping(ERROR_MESSAGE_BAD_FIELD_NAME);
return (Character) index;
}
// ---------------------------------------------------------------------------
// Other methods
// ---------------------------------------------------------------------------
public void setStatus(byte s) {
status = s;
if (status == PIndexedElem.ELEM_DELETED) {
//One of the reason to remove an element from the collection, is
//that the element is deleted. So when the element is deleted, it
// is not no more bound to a PName. Then here we decide to fetch the
// PName in advance but when it is possible.
unSwizzle();
}
}
public boolean equals(Object o) {
if (!(o instanceof CollectionElem)) {
return false;
}
Object objIndex = ((CollectionElem) o).getIndex();
if ((index == null && objIndex != null) ||
(index != null && !index.equals(objIndex))) {
return false;
}
//Store the element value in a local variable in order to avoid
// syncrhonization
Object objElement = element;
//Fetch the real element without causing the loading of the persistent
//instance: do not use the getElement() methods, but direct access to
// the field.
Object ceElem = ((CollectionElem) o).element;
if (objElement == null) {
return ceElem == null;
}
if (ceElem == null) {
return false;
}
if (objElement instanceof PName) {
if (ceElem instanceof PName) {
return objElement.equals(ceElem);
} else if (ceElem instanceof PersistentObjectItf) {
return objElement.equals(((PersistentObjectItf) ceElem).getPName());
} else {
return false;
}
} else if (objElement instanceof PersistentObjectItf) {
if (ceElem instanceof PName) {
Object pn = ((PersistentObjectItf) objElement).getPName();
if (pn == null) {
Logger l = gca.getLogger();
if (l != null) {
l.log(BasicLevel.WARN,
"Internal error: a collection/set/map elemnent is no more persistent and it is impossible to compare it: ",
new RuntimeException());
}
return false;
} else {
return pn.equals(ceElem);
}
} else if (ceElem instanceof PersistentObjectItf) {
return objElement == ceElem;
} else {
return false;
}
} else {
return objElement.equals(ceElem);
}
}
}