/**
* Speedo: an implementation of JDO compliant personality on top of JORM generic
* I/O sub-system.
* 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
*
*
*
* Contact: speedo@objectweb.org
*
* Authors: S.Chassande-Barrioz.
*
*/
package org.objectweb.speedo.metadata;
import java.util.Iterator;
import org.objectweb.asm.Constants;
import org.objectweb.asm.Type;
import org.objectweb.speedo.api.SpeedoException;
import org.objectweb.speedo.api.SpeedoRuntimeException;
import org.objectweb.speedo.generation.enhancer.common.Util;
/**
* This class corresponds to the description of persistent fields.
* @author S.Chassande-Barrioz
*/
public class SpeedoField extends SpeedoCommonField {
/*
* The following constants specify the propagation mode of diverse
* characteristics associated to refernce field persistence.
*/
public final static byte PROPAG_NONE = 0;
public final static byte PROPAG_PERSIST = 1;
public final static byte PROPAG_MERGE = 2;
public final static byte PROPAG_REMOVE = 4;
public final static byte PROPAG_REFRESH = 8;
public final static byte PROPAG_ALL
= PROPAG_PERSIST | PROPAG_MERGE | PROPAG_REMOVE | PROPAG_REFRESH;
public final static byte NO_BI_RELATION = 0;
public final static byte ONE_ONE_BI_RELATION = 1;
public final static byte ONE_MANY_BI_RELATION = 2;
public final static byte MANY_ONE_BI_RELATION = 3;
public final static byte MANY_MANY_BI_RELATION = 4;
public final static byte ONE_REFERENCE = 5;
public final static byte MANY_REFERENCE = 6;
public final static byte UNKNOWN = 0;
public final static byte NONE = 1;
public final static byte PERSISTENT = 2;
public final static String[] PERSISTENCE_STATUS
= {"UNKNOWN", "NONE", "PERSISTENT"};
/**
* @param s is a string representation of a persistence status
* @return the constant value corresponding to the persistence status.
*/
public static byte parsePersistenceStatus(String s) {
for (byte i = 0; i < PERSISTENCE_STATUS.length; i++) {
if (PERSISTENCE_STATUS[i].equalsIgnoreCase(s)) {
return i;
}
}
return UNKNOWN;
}
public static String parsePersistenceStatus(byte ps) {
return PERSISTENCE_STATUS[ps];
}
/**
* visibility of the field (public | protected | private | static ...)
* @see Constants#ACC_PUBLIC
* @see Constants#ACC_PRIVATE
* @see Constants#ACC_PROTECTED
* @see Constants#ACC_STATIC
* @see Constants#ACC_FINAL
* @see Constants#ACC_TRANSIENT
*/
public int visibility;
/**
* Specify the kind of persistence characteristic should be propagated
* through this field (PERSIST | MERGE | REMOVE | REFRESH).
* @see #PROPAG_ALL
* @see #PROPAG_PERSIST
* @see #PROPAG_MERGE
* @see #PROPAG_REMOVE
* @see #PROPAG_REFRESH
* @see #PROPAG_NONE
*/
public byte propagate;
/**
* Type of the persistent field
* @see Type#getDescriptor()
*/
public String type;
/**
* is the index of the persistent field. This field is computed through a
* MI visitor.
*/
public int number;
/**
* Attribute persistence-modifier in the XML file.
*/
public byte persistenceStatus;
/**
* Boolean indicating if the field is a primary key.
*/
public boolean primaryKey;
/**
* Attribute null-value in the XML file.
*/
public byte nullValue;
/**
* This boolean indicates if the field is in the default fetch group.
* (not managed)
*/
public boolean defaultFetchGroup;
/**
* Recursive fetchgroups are controlled by the depth attribute. A depth of 0 (the default)
* will fetch the whole graph of instances reachable from this field.
*/
public int depth;
public String fetchGroup;
/**
* Attribute embedded of the XML file. (not managed)
*/
public boolean embedded;
/**
* Attribute value-strategy
*/
public String valueStrategy;
/**
* Attribute sequence
*/
public String sequence;
/**
* Type of the relation containinig the persistent field
* @see #NO_BI_RELATION
* @see #ONE_ONE_BI_RELATION
* @see #ONE_MANY_BI_RELATION
* @see #MANY_ONE_BI_RELATION
* @see #MANY_MANY_BI_RELATION
*/
public byte relationType;
/**
* Is the name of the field which composes with the current field, a
* bidirectional relation ship.
*/
public String reverseField;
/**
* Indicates if the coherence of bidirectional relationship must be assumed
* by Speedo.
*/
public boolean isCoherentReverseField = false;
/**
* Indicates if the field has to be deleted when its referencer is deleted.
*/
public boolean isCascadeDelete = false;
/**
* In case of bi directional relationship the mapping of this field can be
* defined since the mapping of the reverse field. In this case the #columns
* field is null and this field is equals to 'true'.
* @see #columns
* @see #join
*/
public boolean mappedByReversefield;
public SpeedoField() {
SpeedoDefaults.setDefaults(this);
}
/**
* Transforms a SpeedoField into a String.
* @return the String corresponding to the SpeedoField.
*/
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("SpeedoField");
sb.append("name: ").append(modifier()).append(" ").append(name);
if (relationType != NO_BI_RELATION) {
if ((relationType == ONE_REFERENCE) || (relationType == MANY_REFERENCE)) {
sb.append(", referenceType: ").append(relationType);
} else {
sb.append(", relationType: ").append(relationType);
sb.append(", reverseField: ").append(reverseField);
sb.append(", coherent: ").append(isCoherentReverseField);
}
}
if (persistenceStatus != SpeedoField.PERSISTENT) {
sb.append(", persistenceModifier: ").append(persistenceStatus);
}
if (primaryKey) {
sb.append(", primaryKey");
}
if (nullValue != SpeedoNullValue.NONE) {
sb.append(", nullValue: ").append(nullValue);
}
if (fetchGroup != null) {
sb.append(", fetchGroup: ").append(fetchGroup);
}
if (depth != 0) {
sb.append(", depth: ").append(depth);
}
if (valueStrategy != null) {
sb.append(", valueStrategy: ").append(valueStrategy);
}
sb.append(", sequence: ").append(sequence);
if (jdoTuple != null)
sb.append(jdoTuple.toString());
if (columns != null) {
for (int i = 0; i < columns.length; i++) {
sb.append(", column[").append(i).append("]=(");
sb.append(columns[i]).append(")");
}
} else if (mappedByReversefield) {
}
//sb.append(", defaultFetchGroup: ").append(defaultFetchGroup);
//sb.append(", embedded: ").append(embedded);
return sb.toString();
}
/**
* Returns the field's signature with a public modifier.
* @return the String containing the field' signature with a public modifier.
*/
public String publicSignature() {
int publicAccess = visibility;
publicAccess &= ~(Constants.ACC_PRIVATE | Constants.ACC_PROTECTED);
publicAccess |= Constants.ACC_PUBLIC;
return Util.modifier(publicAccess) + type() + " " + name;
}
/**
* Returns the field's signature with a private modifier.
* @return the String containing the field' signature with a private modifier.
*/
public String privateSignature() {
int privateAccess = visibility;
privateAccess &= ~(Constants.ACC_PUBLIC | Constants.ACC_PROTECTED);
privateAccess |= Constants.ACC_PRIVATE;
return Util.modifier(privateAccess) + type() + " " + name;
}
/**
* Returns the field's modifier
* @return the String representing the modifier (<code>public</code>,
* <code>private</code>, <code>protected</code>)
*/
public String modifier() {
return Util.modifier(visibility);
}
/**
* Returns the type of the field.
* @return type of the field.
*/
public String type() {
return Util.type(Type.getType(type));
}
public SpeedoField getReverseField() throws SpeedoException {
return getFieldOfTheReferencedClass(reverseField);
}
public SpeedoField getFieldOfTheReferencedClass(String fieldName) throws SpeedoException {
String className = null;
if (jdoTuple != null) {
if (jdoTuple instanceof SpeedoCollection) {
className = ((SpeedoCollection) jdoTuple).elementType;
} else if (jdoTuple instanceof SpeedoMap) {
className = (String) ((SpeedoMap) jdoTuple).valueType;
} else if (jdoTuple instanceof SpeedoArray) {
className = Util.type(Type.getType(type));
}
} else {
className = Util.type(Type.getType(type));
}
SpeedoClass sc = moClass.getSpeedoClassFromContext(className);
if (sc == null) {
throw new SpeedoException("No persistent class '" + className + "' found: " + getSourceDesc());
}
return (SpeedoField) sc.fields.get(fieldName);
}
public String getSourceDesc() {
StringBuffer sb = new StringBuffer();
sb.append("field '").append(name);
sb.append("' in class '").append(moClass.getFQName());
sb.append("' in desc '");
sb.append(moClass.moPackage.xmlDescriptor.xmlFile).append("'");
return sb.toString();
}
public void addColumn(SpeedoColumn col) {
columns = (SpeedoColumn[]) addInArray(col, columns, SpeedoColumn[].class);
}
public String getClassName() {
return Type.getType(type).getClassName();
}
public SpeedoClass getReferencedClass() {
if (jdoTuple == null) {
return moClass.getSpeedoClassFromContext(getClassName());
} else if (jdoTuple instanceof SpeedoCollection) {
return moClass.getSpeedoClassFromContext(((SpeedoCollection) jdoTuple).elementType);
} else if (jdoTuple instanceof SpeedoMap) {
return moClass.getSpeedoClassFromContext(((SpeedoMap) jdoTuple).valueType);
} else {
return null;
}
}
}