FileDocCategorySizeDatePackage
MappingClassElementImpl.javaAPI DocGlassfish v2 API35082Fri May 04 22:34:44 BST 2007com.sun.jdo.api.persistence.model.mapping.impl

MappingClassElementImpl

public class MappingClassElementImpl extends MappingElementImpl implements MappingClassElement
author
Mark Munro
author
Rochelle Raccah
version
%I%

Fields Summary
public static final int
CLONE_FIELDS
public static final int
CLONE_DEEP
public static final int
CLONE_MASK
public static final int
NAVIGABLE
com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement
_persistenceElement
private boolean
_isModified
private int
_properties
private ArrayList
_tables
private ArrayList
_fields
private static final int
CURRENT_VERSION_NO
The current version number. Note: Please increment this if there are any changes in the mapping model that might cause incompatibilities to older versions.
private int
versionNo
Version number of this MappingClassElementImpl object. This number is set by the initilaizer of the declaration or set by the archiver when reading a mapping file.
private String
_databaseRoot
The database root for this MappingClassElement. The database root is the schema name of of all the db elements attached to this MappingClassElement.
private int
_consistencyLevel
Consistency Level of this MappingClassElement.
Constructors Summary
public MappingClassElementImpl()
Create new MappingClassElementImpl with no corresponding persistence element or name. This constructor should only be used for cloning and archiving.


	
	/*
	// possibly for EJB use later
	// private String EJBName;
	// which of these (one from desc, one from config)?
	// public Class finderClass;
	// private String finderClass;
	// private Class finderClassType;
	// public static final String DEFAULT_JAVA_FINDERCLASS ="not yet implemented";
	// end possibly for EJB use later
	*/

	// possibly for sequence/identity fields later
	// public ColumnElement uniqueIDCol;

	                       	 
	  
	
		this((String)null);
	
public MappingClassElementImpl(String name)
Creates new MappingClassElementImpl with the corresponding name

param
name the name of the element

		super(name);
		_consistencyLevel = NONE_CONSISTENCY;
		_properties = _properties | NAVIGABLE;
	
public MappingClassElementImpl(com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement element)
Creates new MappingClassElementImpl with a corresponding PersistenceClassElement

param
element the persistence element with which to be associated

		this((element != null) ? element.getName() : null);
		setPersistenceElement(element);
	
Methods Summary
public voidaddField(MappingFieldElement field)
Adds a field to the list of fields in this mapping class.

param
field field element to be added
exception
ModelException if impossible

		ArrayList fields = getFields();

		if (!fields.contains(field))
		{
			try
			{
				fireVetoableChange(PROP_FIELDS, null, null);
				fields.add(field);
				firePropertyChange(PROP_FIELDS, null, null);
			}
			catch (PropertyVetoException e)
			{
				throw new ModelVetoException(e);
			}
		}
	
public MappingReferenceKeyElementaddSecondaryTable(MappingTableElement parentTable, TableElement table)
Adds a reference to the supplied table as a secondary table for this mapping class. It creates a MappingReferenceKeyElement for the supplied primary/secondary table pair.

param
parent mapping table element which should also be the primary table.
param
table table element to be used as a secondary table.
exception
ModelException if impossible

		ArrayList tables = getTables();

		if ((parentTable == null) || (table == null))
		{
			throw new ModelException(I18NHelper.getMessage(getMessages(), 
				"mapping.element.null_argument"));				// NOI18N
		}
		else if (!tables.contains(parentTable))
		{
			throw new ModelException(I18NHelper.getMessage(getMessages(), 
				"mapping.table.parent_table_not_found", 		// NOI18N
				parentTable.getTable()));
		}
		else
		{
			// Check the parent table's reference keys to make sure that this
			// secondary table has not already been added to this parent table.
			// If it has, throw an exception
			Iterator iterator = parentTable.getReferencingKeys().iterator();
			MappingTableElement mappingTable = 
				new MappingTableElementImpl(table, this);
			MappingReferenceKeyElement key = 
				new MappingReferenceKeyElementImpl(mappingTable);

			while (iterator.hasNext())
			{
				MappingTableElement compareTable = 
					((MappingReferenceKeyElement)iterator.next()).getTable();

				if (compareTable.isEqual(table))
				{
					throw new ModelException(I18NHelper.getMessage(
						getMessages(), 
						"mapping.table.secondary_table_defined", 	// NOI18N
						new Object[]{table, parentTable.getTable()}));
				}
			}

			try
			{
				fireVetoableChange(PROP_TABLES, null, null);
				parentTable.addReferencingKey(key);
				tables.add(mappingTable);
				firePropertyChange(PROP_TABLES, null, null);
			}
			catch (PropertyVetoException e)
			{
				throw new ModelVetoException(e);
			}

			return key;
		}
	
public voidaddTable(TableElement table)
Convenience method which accepts a table element and attempts to add it as either a primary or secondary table depending on the existing list of tables and the foreign keys for the table.

param
table table element to be added as either a primary or secondary table.
exception
ModelException if impossible

		if (table != null)
		{
			ArrayList tables = getTables();

			// If the table list is empty, this should be the primary table
			if (tables.isEmpty())
				setPrimaryTable(table);
			else
			{
				HashMap newSecondaryTables = new HashMap();
				Iterator iterator = tables.iterator();
				boolean found = false;

				// If this table has already been added just skip it and return
				while (iterator.hasNext())
					if (((MappingTableElement)iterator.next()).isEqual(table))
						return;

				// Add the table as a secondary table as long as there are
				// relevant fks setup. Otherwise, throw an exception
				iterator = tables.iterator();
				while (iterator.hasNext())
				{
					MappingTableElement mappingTable = 
						(MappingTableElement)iterator.next();
					String absoluteTableName = NameUtil.getAbsoluteTableName(
						_databaseRoot, mappingTable.getTable());
					ForeignKeyElement[] foreignKeys = TableElement.forName(
						absoluteTableName).getForeignKeys();
					int i, count = 
						((foreignKeys != null) ? foreignKeys.length : 0);

					for (i = 0; i < count; i++)
					{
						ForeignKeyElement fk = foreignKeys[i];

						if (table == fk.getReferencedTable())
						{
							// store it so it can be added after we finish
							// iterating the array (can't now because of 
							// concurrent modification restrictions)
							newSecondaryTables.put(mappingTable, fk);
							found = true;
						}
					}
				}

				if (found)	// add the secondary tables now
				{
					iterator = newSecondaryTables.keySet().iterator();
					
					while (iterator.hasNext())
					{		
						MappingTableElement mappingTable = 
							(MappingTableElement)iterator.next();
						MappingReferenceKeyElement refKey = 
							addSecondaryTable(mappingTable, table);

						refKey.addColumnPairs(((ForeignKeyElement)
							newSecondaryTables.get(mappingTable)).
							getColumnPairs());
					}

				}
				else
				{
					throw new ModelException(I18NHelper.getMessage(
						getMessages(), 
						"mapping.table.foreign_key_not_found", table)); // NOI18N
				}
			}
		}
		else
		{
			throw new ModelException(I18NHelper.getMessage(getMessages(), 
				"mapping.table.null_argument"));					// NOI18N
		}
	
protected final voidfirePropertyChange(java.lang.String name, java.lang.Object o, java.lang.Object n)
Fires property change event. This method overrides that of MappingElementImpl to update the mapping class element's modified status.

param
name property name
param
o old value
param
n new value

		// even though o == null and n == null will signify a change, that 
		// is consistent with PropertyChangeSupport's behavior and is 
		// necessary for this to work
		boolean noChange = ((o != null) && (n != null) && o.equals(n));

		super.firePropertyChange(name, o, n);

		if (!(PROP_MODIFIED.equals(name)) && !noChange)
			setModified(true);
	
protected final voidfireVetoableChange(java.lang.String name, java.lang.Object o, java.lang.Object n)
Fires vetoable change event. This method overrides that of MappingElementImpl to give listeners a chance to block changes on the mapping class element modified status.

param
name property name
param
o old value
param
n new value
exception
PropertyVetoException when the change is vetoed by a listener

		// even though o == null and n == null will signify a change, that 
		// is consistent with PropertyChangeSupport's behavior and is 
		// necessary for this to work
		boolean noChange = ((o != null) && (n != null) && o.equals(n));

		super.fireVetoableChange(name, o, n);

		if (!(PROP_MODIFIED.equals(name)) && !noChange)
			fireVetoableChange(PROP_MODIFIED, Boolean.FALSE, Boolean.TRUE);
	
public static MappingClassElementforName(java.lang.String name, Model model)
Returns the mapping class element associated with the class with the given string name, using the given model object to look it up.

param
name the fully qualified name of the desired class
param
model the model object to be used to look it up
return
mapping class element representing the desired class

		return model.getMappingClass(name);
	
public intgetConsistencyLevel()
Gets the consistency level of this mapping class.

return
the consistency level, one of {@link #NONE_CONSISTENCY}, {@link #CHECK_MODIFIED_AT_COMMIT_CONSISTENCY}, {@link #CHECK_ALL_AT_COMMIT_CONSISTENCY}, {@link #LOCK_WHEN_MODIFIED_CONSISTENCY}, {@link #LOCK_WHEN_MODIFIED_CHECK_ALL_AT_COMMIT_CONSISTENCY}, {@link #LOCK_WHEN_LOADED_CONSISTENCY}, or {@link #VERSION_CONSISTENCY}. The default is {@link #NONE_CONSISTENCY}.

 return _consistencyLevel; 
public java.lang.StringgetDatabaseRoot()
Returns the name of the SchemaElement which represents the database used by the tables mapped to this mapping class.

return
the name of the database root for this mapping class

 return _databaseRoot; 
public MappingFieldElementgetField(java.lang.String name)
Scans through this mapping class looking for a field whose name matches the name passed in.

param
name name of the field to find.
return
the mapping field whose name matches the name parameter

		Iterator fieldIterator = getFields().iterator();

		while (fieldIterator.hasNext())
		{
			MappingFieldElement field = 
				(MappingFieldElement)fieldIterator.next();

			if (name.equals(field.getName()))
				return field;
		}

		return null;
	
public java.util.ArrayListgetFields()
Returns the list of fields (MappingFieldElements) in this mapping class. This list includes both local and relationship fields.

return
the mapping fields in this mapping class

		if (_fields == null)
			_fields = new ArrayList();

		return _fields;
	
public java.lang.StringgetKeyClass()
Get the fully qualified name of the primary key class for this class element. This value is only used if getObjectIdentityType returns APPLICATION_IDENTITY

return
the fully qualified key class name, null if the identity type is not managed by the application
see
PersistenceClassElement#setObjectIdentityType
see
PersistenceClassElement#APPLICATION_IDENTITY

		return getPersistenceElement().getKeyClass();
	
public final com.sun.jdo.api.persistence.model.jdo.PersistenceClassElementgetPersistenceElement()

return
persistence class element for this mapping class element

		return _persistenceElement;
	
public intgetProperties()

 return _properties; 
public MappingTableElementgetTable(java.lang.String name)
Scans through this mapping class looking for a table whose name matches the name passed in.

param
name name of the table to find.
return
the meta data table whose name matches the name parameter

		Iterator tableIterator = getTables().iterator();

		while (tableIterator.hasNext())
		{
			MappingTableElement table = 
				(MappingTableElement)tableIterator.next();

			if (table.getName().equals(name))
				return table;
		}

		return null;
	
public java.util.ArrayListgetTables()
Returns the list of tables (MappingTableElements) used by this mapping class.

return
the meta data tables for this mapping class

		if (_tables == null)
			_tables = new ArrayList();

		return _tables;
	
public java.util.ListgetVersionFields()
Returns the list of version fields (MappingFieldElements) in this mapping class. This list only includes fields if the consistency level is {@link #VERSION_CONSISTENCY}.

return
the version fields in this mapping class

		List versionFields = new ArrayList();

		if (VERSION_CONSISTENCY == getConsistencyLevel())
		{
			Iterator iterator = getFields().iterator();

			while (iterator.hasNext())
			{
				MappingFieldElement fieldCandidate =
					(MappingFieldElement)iterator.next();

				if (fieldCandidate.isVersion())
					versionFields.add(fieldCandidate);
			}
		}

		return versionFields;
	
public intgetVersionNumber()
Returns the version number of this MappingClassElement object. Please note, the returned version number reflects the version number at the last save, NOT the version number of the memory representation.

return
version number

 return versionNo; 
public booleanhasOldVersionNumber()
Returns true if the version number of this MappingClassElement object is older than the current version number of the archiving scheme.

see
#getVersionNumber
return
true if it is in need of updating, false otherwise

		return (getVersionNumber() < CURRENT_VERSION_NO);
	
public booleanisModified()
Gets the modified flag for this mapping class.

return
true if there have been (property) changes to this class, false otherwise.

 return _isModified; 
public booleanisNavigable()
Gets the navigable flag for this mapping class.

return
true if lazy initialization will be used, false if access to a non-fetched field will result in an exception. The default is true.

 return ((_properties & NAVIGABLE) > 0); 
public voidpostUnarchive()
This method is called after a MappingClassElement is unarchived from a .mapping file. This method provides a hook to do any checking (version number checking) and conversion after unarchiving.

exception
ModelException if impossible

		// check version number
		switch (versionNo)
		{
			case 0: // outdated version number
			case 1: // outdated version number
				throw new ModelException (I18NHelper.getMessage(getMessages(), 
					"file.incompatible_version", getName()));	//NOI18N
			case 2:
				// Boston format => convert to Pilsen format
				stripSchemaName();
				break;
			case 3:	// same as 4 except package names are different
			case 4:	// same as 5 except version field not a choice for MFE
			case MappingClassElementImpl.CURRENT_VERSION_NO:
				// OK
				break;
			default: // version number is unknown
				throw new ModelException (I18NHelper.getMessage(getMessages(), 
					"file.incompatible_version", getName()));	//NOI18N
		}
	
public voidpreArchive()
This method is called prior to storing a MappingClassElement in a .mapping file. This method provides a hook to do any conversion before archiving. Note, the signature of preArchive in the interface MappingClassElement includes a throws clause (ModelException), but the actual implementation does not throw an exception.

		// update version number
		setVersionNumber(CURRENT_VERSION_NO);
	
public voidremoveField(MappingFieldElement field)
Removes a field from the list of fields in this mapping class.

param
field field element to be removed
exception
ModelException if impossible

		try
		{
			fireVetoableChange(PROP_FIELDS, null, null);

			if (!getFields().remove(field))
			{
				throw new ModelException(I18NHelper.getMessage(getMessages(), 
					"mapping.element.element_not_removed", field));	// NOI18N
			}

			firePropertyChange(PROP_FIELDS, null, null);
		}
		catch (PropertyVetoException e)
		{
			throw new ModelVetoException(e);
		}
	
public voidremoveTable(MappingTableElement table)
Removes the reference to the supplied table as a mapped table for this mapping class. This works whether the table is the primary table or a secondary table.

param
table mapping table element to be removed from this mapping class.
exception
ModelException if impossible

		if (table != null)
		{
			Collection tables = getTables();
			Iterator iterator = null;
			boolean found = false;

			try
			{
				fireVetoableChange(PROP_TABLES, null, null);
				found = tables.remove(table);
				firePropertyChange(PROP_TABLES, null, null);
			}
			catch (PropertyVetoException e)
			{
				throw new ModelVetoException(e);
			}

			// remove all references to this table
			iterator = tables.iterator();
			while (iterator.hasNext())
			{
				MappingTableElement nextTable =
					(MappingTableElement)iterator.next();

				nextTable.removeReference(table);
			}

			if (found)	// remove any fields mapped to that table
			{
				ArrayList fieldsToRemove = new ArrayList();

				iterator = getFields().iterator();
				while (iterator.hasNext())
				{
					MappingFieldElementImpl mappingField = 
						(MappingFieldElementImpl)iterator.next();
					
					if (mappingField.isMappedToTable(table))
						fieldsToRemove.add(mappingField);
				}

				iterator = fieldsToRemove.iterator();
				while (iterator.hasNext())
				{
					MappingFieldElement mappingField = 
						(MappingFieldElement)iterator.next();
					boolean versionField = mappingField.isVersion();

					removeField(mappingField);

					// if it is a version field, add back an unmapped
					// field which retains the version flag setting
					if (versionField)
					{
						mappingField = new MappingFieldElementImpl(
							mappingField.getName(), this);
						mappingField.setVersion(true);
						addField(mappingField);
					}
				}
			}
			else
			{
				throw new ModelException(I18NHelper.getMessage(getMessages(), 
					"mapping.element.element_not_removed", table));	// NOI18N
			}
		}
		else
		{
			throw new ModelException(I18NHelper.getMessage(getMessages(), 
				"mapping.element.null_argument"));				// NOI18N
		}
	
public voidsetConsistencyLevel(int level)
Set the consistency level of this mapping class.

param
level an integer indicating the consistency level, one of: {@link #NONE_CONSISTENCY},{@link #CHECK_MODIFIED_AT_COMMIT_CONSISTENCY}, {@link #CHECK_ALL_AT_COMMIT_CONSISTENCY}, {@link #LOCK_WHEN_MODIFIED_CONSISTENCY}, {@link #LOCK_WHEN_MODIFIED_CHECK_ALL_AT_COMMIT_CONSISTENCY}, {@link #LOCK_WHEN_LOADED_CONSISTENCY}, or {@link #VERSION_CONSISTENCY}.
exception
ModelException if impossible.

		Integer old = new Integer(getConsistencyLevel());
		Integer newLevel = new Integer(level);

		try
		{
			fireVetoableChange(PROP_CONSISTENCY, old, newLevel);
			_consistencyLevel = level;
			firePropertyChange(PROP_CONSISTENCY, old, newLevel);
		}
		catch (PropertyVetoException e)
		{
			throw new ModelVetoException(e);
		}
	
public voidsetDatabaseRoot(SchemaElement root)
Set the database root for this MappingClassElement. The root represents the database used by the tables mapped to this mapping class.

param
root the new database root
exception
ModelException if impossible

		String old = getDatabaseRoot();
		String newRoot = ((root != null) ? root.getName().getFullName() : null);
		
		try
		{
			fireVetoableChange(PROP_DATABASE_ROOT, old, newRoot);
			_databaseRoot = newRoot;
			firePropertyChange(PROP_DATABASE_ROOT, old, newRoot);
		}
 		catch (PropertyVetoException e)
		{
			throw new ModelVetoException(e);
		}
	
public voidsetFields(java.util.ArrayList fields)
Set the list of fields (MappingFieldElements) in this mapping class. This method should only be used internally and for cloning and archiving.

param
fields the list of mapping fields in this mapping class

 _fields = fields; 
public voidsetModified(boolean flag)
Set the modified flag for this mapping class to flag. This is usually set to true by property changes and false after a save.

param
flag if true, this class is marked as modified; if false, it is marked as unmodified.

		boolean oldFlag = isModified();

		if (flag != oldFlag)
		{
			_isModified = flag;
			firePropertyChange(PROP_MODIFIED, JavaTypeHelper.valueOf(oldFlag), 
				JavaTypeHelper.valueOf(flag));
		}
	
public voidsetNavigable(boolean flag)
Set the navigable flag for this mapping class to flag.

param
flag if true, lazy initialization will be used; if false, access to a non-fetched field will result in an exception.
exception
ModelException if impossible

		Boolean old = JavaTypeHelper.valueOf(isNavigable());
		Boolean newFlag = JavaTypeHelper.valueOf(flag);

		try
		{
			fireVetoableChange(PROP_NAVIGABLE, old, newFlag);
			_properties = (flag) ? 
				(_properties | NAVIGABLE) : (_properties & ~NAVIGABLE);
			firePropertyChange(PROP_NAVIGABLE, old, newFlag);
		}
		catch (PropertyVetoException e)
		{
			throw new ModelVetoException(e);
		}
	
public voidsetPersistenceElement(com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement element)
Set the persistence class element for this mapping class element.

param
element the persistence class element

		_persistenceElement = element;
	
public voidsetPrimaryTable(TableElement table)
Set the primary table for this mapping class to the supplied table.

param
table table element to be used as the primary table.
exception
ModelException if impossible

		ArrayList tables = getTables();

		if (!tables.isEmpty())
		{
			throw new ModelException(I18NHelper.getMessage(getMessages(), 
				"mapping.table.primary_table_defined", table));	// NOI18N
		}
		else
		{
			UniqueKeyElement key = table.getPrimaryKey();
			MappingTableElement mappingTable = 
				new MappingTableElementImpl(table, this);
			SchemaElement schema = table.getDeclaringSchema();
			String currentRoot = getDatabaseRoot();

			if (currentRoot == null)	// set database root
				setDatabaseRoot(schema);
			else if (!currentRoot.equals(schema.getName().getFullName()))
			{
				// if database root was set before, it must match
				throw new ModelException(I18NHelper.getMessage(
					getMessages(), "mapping.table.schema_mismatch",	// NOI18N
					table.toString(), currentRoot));
			}

			try
			{
				fireVetoableChange(PROP_TABLES, null, null);
				tables.add(mappingTable);
				firePropertyChange(PROP_TABLES, null, null);
			}
			catch (PropertyVetoException e)
			{
				throw new ModelVetoException(e);
			}

			//	If can't find a primary key, settle for first unique key.
			if (key == null)
			{
				UniqueKeyElement[] uniqueKeys = table.getUniqueKeys();

				if ((uniqueKeys != null) && (uniqueKeys.length > 0))
					key = uniqueKeys[0];
			}

			if (key == null)
			{
				//	This is a warning -- we can still use the table but we 
				//	cannot perform update operations on it.  Also the user  
				//	may define the key later.
			}
			else
			{
				ColumnElement[] columns = key.getColumns();
				int i, count = ((columns != null) ? columns.length : 0);

				for (i = 0; i < count; i++)
					mappingTable.addKeyColumn(columns[i]);
			}
		}
	
private voidsetVersionNumber(int version)
Set the version number of this MappingClassElement.

param
version the new version number

 versionNo = version; 
protected voidstripSchemaName()
Boston to Pilsen conversion. This method converts the absolute db element names to relative names and stores the database root (meaning the schema name) in the MappingClassElement. The method is recursively called for all MappingTableElements and MappingFieldElements attached to this MappingClassElement.

		String schemaName = null;

		// calculate schemaName from first MappingTableElement
		if (_tables != null && !_tables.isEmpty())
		{
			schemaName = NameUtil.getSchemaName(
				((MappingTableElement)_tables.get(0)).getTable());
		}

		// set the schemaName as database root
		_databaseRoot = schemaName;

		// do not change the  _isModified flag

		// handle _tables
		if (_tables != null)
		{
			Iterator i = _tables.iterator();
			while (i.hasNext())
				((MappingTableElementImpl)i.next()).stripSchemaName();
		}
		
		// handle _fields
		if (_fields != null)
		{
			Iterator i = _fields.iterator();
			while (i.hasNext())
				((MappingFieldElementImpl)i.next()).stripSchemaName();
		}
	
protected static java.util.ArrayListtoColumnObjects(java.lang.String schemaName, java.util.ArrayList columnNames)
Accept an arraylist of column names and return an array list containing the corresponding column or column pair objects.

param
schemaName the database root used to find the column objects
param
columnNames array of column names.
return
an array of corresponding column objects
see
org.netbeans.modules.dbschema.TableElement#forName
see
org.netbeans.modules.dbschema.TableElement#getMember

		Iterator iterator = columnNames.iterator();
		ArrayList objects = new ArrayList();

		while (iterator.hasNext())
		{
			String columnName = (String)iterator.next();
			String absoluteColumnName = 
				NameUtil.getAbsoluteMemberName(schemaName, columnName);
			final TableElement table =
				TableElement.forName(NameUtil.getTableName(absoluteColumnName));

			objects.add(table.getMember(
				DBIdentifier.create(absoluteColumnName)));
		}

		return objects;