com.sun.jdo.api.persistence.model.util.ModelValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portion Copyright [2018-2019] Payara Foundation and/or affiliates
/*
* ModelValidator.java
*
* Created on September 22, 2000, 12:49 PM
*/
package com.sun.jdo.api.persistence.model.util;
import com.sun.jdo.api.persistence.model.Model;
import com.sun.jdo.api.persistence.model.jdo.PersistenceClassElement;
import com.sun.jdo.api.persistence.model.jdo.PersistenceFieldElement;
import com.sun.jdo.api.persistence.model.jdo.RelationshipElement;
import com.sun.jdo.api.persistence.model.mapping.*;
import com.sun.jdo.spi.persistence.utility.JavaTypeHelper;
import com.sun.jdo.spi.persistence.utility.logging.Logger;
import org.glassfish.common.util.StringHelper;
import org.glassfish.persistence.common.I18NHelper;
import org.netbeans.modules.dbschema.*;
import org.netbeans.modules.dbschema.util.NameUtil;
import org.netbeans.modules.dbschema.util.SQLTypeUtil;
import java.lang.reflect.Modifier;
import java.util.*;
/**
*
* @author Rochelle Raccah
* @version %I%
*/
public class ModelValidator
{
/** This field holds the model object used for validation */
private Model _model;
/** This field holds the name of the class being validated */
private String _className;
/** This field holds the class loader used to load class
* being validated (if available).
*/
private ClassLoader _classLoader;
/** I18N message handler */
private ResourceBundle _messages;
public ModelValidator (Model model, String className, ResourceBundle bundle)
{
this(model, className, null, bundle);
}
/** Create a new model validator object.
* @param model model object used for validation
* @param className the name of the class being validated
*/
public ModelValidator (Model model, String className,
ClassLoader classLoader, ResourceBundle bundle)
{
_model = model;
_className = className;
_classLoader = classLoader;
_messages = bundle;
}
/**
* Get the model object used for validation.
* @return the model object used for validation
*/
public Model getModel () { return _model; }
/**
* Get the name of the class being validated.
* @return the name of the class being validated
*/
public String getClassName () { return _className; }
/**
* Get the class loader used to load the class being validated.
* @return the class loader of the class being validated
*/
public ClassLoader getClassLoader () { return _classLoader; }
/** @return I18N message handler for this element
*/
protected ResourceBundle getMessages () { return _messages; }
/** Main method used for parsing the combination of java (or class)
* information and mapping/jdo information by running through a subset
* of the full validation check and aborting (and returning
* false
at the first error or warning.
* @return true
if no errors or warnings occur,
* false
otherwise.
* @see #getBasicValidationList
*/
public boolean parseCheck ()
{
Iterator iterator = getBasicValidationList().iterator();
try
{
while (iterator.hasNext())
((ValidationComponent)iterator.next()).validate();
}
catch (ModelValidationException e)
{
LogHelperModel.getLogger().log(Logger.FINER,
"model.parse_error", e); // NOI18N
return false;
}
return true;
}
/** Main method used for validating the combination of java (or class)
* information and mapping/jdo information by running through the full
* validation check and returning a collection of
* ModelValidationExceptions containing any errors or warnings encountered.
* @return a collection of ModelValidationExceptions containing any
* errors or warnings encountered. If no errors or warnings were
* encountered, the collection will be empty, not null
.
* @see #getFullValidationList
*/
public Collection fullValidationCheck ()
{
ArrayList list = new ArrayList();
Iterator iterator = getFullValidationList().iterator();
while (iterator.hasNext())
{
try
{
((ValidationComponent)iterator.next()).validate();
}
catch (ModelValidationException e)
{
list.add(e);
}
}
return Collections.unmodifiableCollection(list);
}
// ================ Validation list construction methods ===============
/** Computes and returns a collection of ValidationComponents
* representing the tests to be performed during parse.
* @return a collection of ValidationComponents representing the
* tests to be performed during parse.
* @see #getDatabaseValidationList
* @see #getFieldsValidationList
* @see #getFullValidationList
*/
public Collection getBasicValidationList ()
{
ArrayList list = new ArrayList();
String className = getClassName();
list.add(createClassExistenceComponent(className));
list.add(createClassPersistenceComponent(className));
list.addAll(getDatabaseValidationList());
list.addAll(getFieldsValidationList());
return Collections.unmodifiableCollection(list);
}
/** Computes and returns a collection of ValidationComponents
* representing the tests to be performed during validation. These
* include all those in the basic list plus those which check
* cardinality and the related classes in more detail.
* @return a collection of ValidationComponents representing the
* tests to be performed during validation.
* @see #getRelatedClassValidationList
* @see #getBasicValidationList
*/
public Collection getFullValidationList ()
{
ArrayList list = new ArrayList(getBasicValidationList());
String className = getClassName();
PersistenceClassElement persistenceClass =
getPersistenceClass(className);
if (persistenceClass != null)
{
PersistenceFieldElement[] fields = persistenceClass.getFields();
int i, count = ((fields != null) ? fields.length : 0);
list.add(createSerializableClassComponent(className));
list.add(createKeyClassComponent(persistenceClass.getKeyClass()));
list.add(createClassMappingComponent(persistenceClass));
list.add(createKeyColumnMappingComponent(persistenceClass));
for (i = 0; i < count; i++)
{
PersistenceFieldElement field = fields[i];
list.add(createFieldCardinalityComponent(field));
list.add(createFieldMappingComponent(field));
list.add(createFieldBlobMappingComponent(field));
list.addAll(getRelatedClassValidationList(field));
}
}
return Collections.unmodifiableCollection(list);
}
// ============= Validation list construction suppport methods ============
/** Computes and returns a collection of ValidationComponents
* representing the database tests to be performed.
* @return a collection of ValidationComponents representing the
* database tests to be performed.
*/
private Collection getDatabaseValidationList ()
{
ArrayList list = new ArrayList();
String className = getClassName();
MappingClassElement mappingClass = getMappingClass(className);
if (mappingClass != null)
{
ArrayList tables = mappingClass.getTables();
int i, count = ((tables != null) ? tables.size() : 0);
MappingTableElement primaryTable = null;
Iterator iterator = null;
list.add(createSchemaExistenceComponent(className));
for (i = 0; i < count; i++)
{
MappingTableElement nextTable =
(MappingTableElement)tables.get(i);
list.add(createTableExistenceComponent(nextTable.getTable()));
if (i == 0)
{
primaryTable = nextTable;
list.add(createPrimaryTableComponent(primaryTable));
}
else
{
MappingReferenceKeyElement referenceKey =
findReferenceKey(primaryTable, nextTable);
if (referenceKey != null)
{
iterator = referenceKey.getColumnPairNames().iterator();
while (iterator.hasNext())
{
list.add(createColumnExistenceComponent(
(String)iterator.next()));
}
}
}
}
list.add(createVersionConsistencyComponent(mappingClass));
iterator = mappingClass.getFields().iterator();
while (iterator.hasNext())
{
MappingFieldElement nextField =
(MappingFieldElement)iterator.next();
ArrayList allColumns = new ArrayList();
Iterator columnIterator = null;
if (isRelationship(nextField))
{
allColumns.addAll(((MappingRelationshipElement)nextField).
getAssociatedColumns());
}
allColumns.addAll(nextField.getColumns());
columnIterator = allColumns.iterator();
while (columnIterator.hasNext())
{
list.add(createColumnExistenceComponent(
(String)columnIterator.next(), nextField));
}
}
}
return list;
}
/** Computes and returns a collection of ValidationComponents
* representing the field and relationship tests to be performed.
* @return a collection of ValidationComponents representing the
* field and relationship tests to be performed.
*/
private Collection getFieldsValidationList ()
{
ArrayList list = new ArrayList();
Model model = getModel();
String className = getClassName();
PersistenceClassElement persistenceClass =
getPersistenceClass(className);
if (persistenceClass != null)
{
PersistenceFieldElement[] fields = persistenceClass.getFields();
int i, count = ((fields != null) ? fields.length : 0);
Iterator iterator =
getMappingClass(className).getFields().iterator();
for (i = 0; i < count; i++)
{
PersistenceFieldElement field = fields[i];
list.add(createFieldExistenceComponent(field));
// even though this is really the validation step, we
// only want to add the others if the field exists
if (model.hasField(className, field.getName()))
{
list.add(createFieldPersistenceComponent(field));
list.add(createFieldPersistenceTypeComponent(field));
list.add(createFieldConsistencyComponent(field));
if (isLegalRelationship(field))
{
RelationshipElement rel = (RelationshipElement)field;
/* user modifiable collection class not yet supported
list.add(createCollectionClassComponent(rel));*/
list.add(createElementClassComponent(rel));
list.add(createRelatedClassMatchesComponent(rel));
}
}
}
while (iterator.hasNext())
{
MappingFieldElement field =
(MappingFieldElement)iterator.next();
String fieldName = field.getName();
// only check this if it is not in the jdo model
if (persistenceClass.getField(fieldName) == null)
{
list.add(createFieldExistenceComponent(field));
// even though this is really the validation step, we
// only want to add the others if the field exists
if (model.hasField(className, fieldName))
list.add(createFieldConsistencyComponent(field));
}
if (!isRelationship(field))
list.add(createColumnOverlapComponent(field));
// preliminary fix for CR6239630
if (Boolean.getBoolean("AllowManagedFieldsInDefaultFetchGroup")) // NOI18N
{
// Do nothing - AllowManagedFieldsInDefaultFetchGroup:
// disabled single model validation test;
// may use checked read/write access to managed fields
}
else
{
list.add(createFieldDefaultFetchGroupComponent(field));
}
}
}
return list;
}
/** Computes and returns a collection of ValidationComponents
* representing the related class tests to be performed. Right now,
* these are only included as part of full validation, as they may
* be somewhat time intensive since they compute information about
* other classes as well as this class.
* @return a collection of ValidationComponents representing the
* related class tests to be performed.
*/
private Collection getRelatedClassValidationList (
PersistenceFieldElement field)
{
String relatedClass = getRelatedClass(field);
ArrayList list = new ArrayList();
// even though this is really already included in the validation
// step, we only want to add the extra steps if the field exists
if ((relatedClass != null) &&
getModel().hasField(getClassName(), field.getName()))
{
MappingClassElement relatedClassElement =
getMappingClass(relatedClass);
list.add(createClassExistenceComponent(relatedClass, field));
list.add(createClassPersistenceComponent(relatedClass, field));
list.add(createSchemaExistenceComponent(relatedClass, field));
list.add(createRelatedSchemaMatchesComponent(relatedClass, field));
if (relatedClassElement != null)
{
ArrayList tables = relatedClassElement.getTables();
MappingTableElement primaryTable = null;
boolean hasTables = ((tables != null) && (tables.size() > 0));
if (hasTables)
{
primaryTable = (MappingTableElement)tables.get(0);
list.add(createTableExistenceComponent(
primaryTable.getTable(), field));
}
if (isRelationship(field))
{
RelationshipElement relElement = (RelationshipElement)field;
Object rel = getMappingClass(getClassName()).
getField(field.getName());
list.add(createInverseFieldComponent(relElement));
list.add(createInverseMappingComponent(relElement));
// verify that the columns from the primary table
// of the related class are actually from that table
// since it could have been changed
if ((rel != null) && isRelationship(rel))
{
MappingRelationshipElement relationship =
(MappingRelationshipElement)rel;
ArrayList columns =
relationship.getAssociatedColumns();
Iterator iterator = null;
if ((columns == null) || (columns.size() == 0))
columns = relationship.getColumns();
if (columns != null)
{
List tableNames = new ArrayList();
if (hasTables)
{
Iterator tableIterator = tables.iterator();
while (tableIterator.hasNext())
{
tableNames.add(((MappingTableElement)
tableIterator.next()).getName());
}
}
iterator = columns.iterator();
while (iterator.hasNext())
{
list.add(createRelatedTableMatchesComponent(
relatedClass, field, tableNames,
(String)iterator.next()));
}
}
}
}
}
}
return list;
}
// ================ Validation Component inner classes ===============
/** Create a validation component which can check whether the class exists.
* @param className the class whose existence is being checked
* @param relatedField the relationship field whose class is being checked,
* may be null
in which case we are probably checking the
* same class as the validator is checking overall
* @return the validation component
*/
protected ValidationComponent createClassExistenceComponent (
final String className, final PersistenceFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if ((className == null) ||
!getModel().hasClass(className, getClassLoader()))
{
throw constructClassException(className, relatedField,
"util.validation.class_not_found"); //NOI18N
}
}
};
}
/** Create a validation component which can check whether the class exists.
* @param className the class whose existence is being checked
* @return the validation component
*/
protected ValidationComponent createClassExistenceComponent (
final String className)
{
return createClassExistenceComponent(className, null);
}
/** Create a validation component which can check the class persistence.
* @param className the class whose persistence is being checked
* @param relatedField the relationship field whose class is being checked,
* may be null
in which case we are probably checking the
* same class as the validator is checking overall
* @return the validation component
*/
protected ValidationComponent createClassPersistenceComponent (
final String className, final PersistenceFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
Model model = getModel();
if ((className != null) &&
model.hasClass(className, getClassLoader()))
{
String key = null;
if (!isPersistent(className))
key = "util.validation.class_not_persistence_capable";//NOI18N
else if (!model.isPersistenceCapableAllowed(className))
key = "util.validation.class_not_allowed";//NOI18N
if (key != null)
{
throw constructClassException(
className, relatedField, key);
}
}
}
};
}
/** Create a validation component which can check the class persistence.
* @param className the class whose persistence is being checked
* @return the validation component
*/
protected ValidationComponent createClassPersistenceComponent (
final String className)
{
return createClassPersistenceComponent(className, null);
}
/** Create a validation component which can check whether the field exists.
* @param fieldName the field whose existence is being checked
* @return the validation component
*/
protected ValidationComponent createFieldExistenceComponent (
final String fieldName)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (!getModel().hasField(getClassName(), fieldName))
{
throw constructFieldException(fieldName,
"util.validation.field_not_found"); //NOI18N
}
}
};
}
/** Create a validation component which can check whether the field exists.
* @param field the field whose existence is being checked
* @return the validation component
*/
protected ValidationComponent createFieldExistenceComponent (Object field)
{
return createFieldExistenceComponent(field.toString());
}
/** Create a validation component which can check whether the field is
* persistent.
* @param field the field whose persistence is being checked
* @return the validation component
*/
protected ValidationComponent createFieldPersistenceComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
boolean isPersistent = (PersistenceFieldElement.PERSISTENT ==
field.getPersistenceType());
String fieldName = field.getName();
if (isPersistent &&
!isPersistentAllowed(getClassName(), fieldName))
{
throw constructFieldException(fieldName,
"util.validation.field_persistent_not_allowed");//NOI18N
}
}
};
}
/** Create a validation component which can check whether the field is
* consistent (field in both models or relationship in both).
* @param field the field whose consistency is being checked
* @return the validation component
*/
protected ValidationComponent createFieldConsistencyComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String fieldName = field.getName();
String className = getClassName();
boolean isLegallyPersistent =
isPersistentAllowed(className, fieldName);
if (isLegallyPersistent)
{
MappingClassElement mappingClass =
getMappingClass(className);
MappingFieldElement mappingElement =
((mappingClass != null) ?
mappingClass.getField(fieldName) : null);
if (mappingElement != null)
{
boolean jdoIsRelationship = isLegalRelationship(field);
if (jdoIsRelationship != isRelationship(mappingElement))
{
throw constructFieldException(fieldName,
"util.validation.field_type_inconsistent"); //NOI18N
}
}
}
}
};
}
/** Create a validation component which can check whether the field is
* consistent (if in mapping model but not jdo, it is a problem).
* @param field the field whose consistency is being checked
* @return the validation component
*/
protected ValidationComponent createFieldConsistencyComponent (
final MappingFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (field != null)
{
String fieldName = field.getName();
PersistenceClassElement persistenceClass =
getPersistenceClass(getClassName());
PersistenceFieldElement persistenceElement =
((persistenceClass != null) ?
persistenceClass.getField(fieldName) : null);
if (persistenceElement == null)
{
throw constructFieldException(fieldName,
"util.validation.field_model_inconsistent");//NOI18N
}
}
}
};
}
/** Create a validation component which can check the persistence type
* of the field (whether it is a relationship or not).
* @param field the field whose persistence type is being checked
* @return the validation component
*/
protected ValidationComponent createFieldPersistenceTypeComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String fieldName = field.getName();
String className = getClassName();
boolean isLegallyPersistent =
isPersistentAllowed(className, fieldName);
if (isLegallyPersistent)
{
boolean isRelationship = isRelationship(field);
boolean mustBeRelationship = shouldBeRelationship(field);
if (isRelationship && !mustBeRelationship)
{
throw constructFieldException(fieldName,
"util.validation.field_relationship_not_allowed");//NOI18N
}
else if (!isRelationship && mustBeRelationship)
{
throw constructFieldException(fieldName,
"util.validation.field_type_not_allowed"); //NOI18N
}
}
}
};
}
/** Create a validation component which can check whether the cardinality
* bounds are semantically valid given the relationship field type.
* @param field the relationship whose cardinality bounds are being checked
* @return the validation component
*/
protected ValidationComponent createFieldCardinalityComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (isLegalRelationship(field))
{
RelationshipElement relationship =
(RelationshipElement)field;
String fieldName = field.getName();
boolean nonCollectionRelationship =
!isCollection(getClassName(), fieldName);
int upperBound = (nonCollectionRelationship ?
1 : relationship.getUpperBound());
int lowerBound = relationship.getLowerBound();
MappingRelationshipElement mapping = null;
if ((lowerBound < 0) || (upperBound <= 0) ||
(lowerBound > upperBound))
{
throw constructFieldException(fieldName,
"util.validation.cardinality_invalid"); //NOI18N
}
// now check specific lower bound requirements imposed
// by the mapping
mapping = getMappingRelationship(relationship);
if (nonCollectionRelationship && (lowerBound != 1) &&
(mapping != null) && !isJoin(mapping))
{
// If the non-collection relationship field is exactly
// mapped to a FK, we need to check the nullability
// of the columns. If there are any non-nullable
// columns the lower bound must be 1.
ForeignKeyElement fk = getMatchingFK(mapping);
if ((fk != null) && hasNonNullableColumn(fk))
{
throw constructFieldException(fieldName,
"util.validation.lower_bound_invalid"); //NOI18N
}
}
}
}
/** Returns true
if the specified FK has at least
* one non-nullable column. Please note that the caller is
* responsible for passing a non-null fk argument.
*/
private boolean hasNonNullableColumn (ForeignKeyElement fk)
{
ColumnElement[] localColumns = fk.getLocalColumns();
int count = ((localColumns != null) ? localColumns.length : 0);
for (int i = 0; i < count; i++)
{
if (!localColumns[i].isNullable())
return true;
}
return false;
}
/** Checks whether the specified relationship is exactly mapped
* to a FK. If yes, the method returns the matching FK. If not,
* it returns null
. Please note that the caller is
* responsible for passing a non-null mapping argument.
*/
private ForeignKeyElement getMatchingFK (
MappingRelationshipElement mapping)
{
MappingClassElement mappingClass = mapping.
getDeclaringClass();
String databaseRoot = getSchemaForClass(getClassName());
List pairNames = mapping.getColumns();
List tables = mappingClass.getTables();
if (tables != null)
{
for (Iterator i = tables.iterator(); i.hasNext();)
{
String tableName = ((MappingTableElement)i.next()).
getName();
TableElement table = getTable(tableName, databaseRoot);
ForeignKeyElement fk = getMatchingFK(pairNames, table);
if (fk != null)
return fk;
}
}
return null;
}
/** Checks whether the specified TableElement has a FK that
* exactly matches the list of column pair names.
* @return the matching FK if it exactly matches the list
* of column pairs; null
otherwise.
*/
private ForeignKeyElement getMatchingFK (List pairNames,
TableElement table)
{
ForeignKeyElement[] foreignKeys = (table != null) ?
table.getForeignKeys() : null;
int count = ((foreignKeys != null) ? foreignKeys.length : 0);
for (int i = 0; i < count; i++)
{
if (matchesFK(pairNames, foreignKeys[i]))
return foreignKeys[i];
}
return null;
}
/** Returns true
if the specified list of column
* pair names matches exactly the specified FK.
*/
private boolean matchesFK (List pairNames,
ForeignKeyElement foreignKey)
{
ColumnPairElement[] fkPairs = foreignKey.getColumnPairs();
int fkCount = ((fkPairs != null) ? fkPairs.length : 0);
int count = ((pairNames != null) ? pairNames.size() : 0);
// First check whether the list of fk column pairs has the
// same size than the specified list of columns.
if (fkCount == count)
{
// Now check whether each fk column is included in the
// specified list of columns.
for (int i = 0; i < fkCount; i++)
{
String fkPairName = NameUtil.getRelativeMemberName(
fkPairs[i].getName().getFullName());
if (!pairNames.contains(fkPairName))
return false;
}
return true;
}
return false;
}
};
}
/** Create a validation component which can check whether the field is
* unmapped.
* @param field the field whose mapping is being checked
* @return the validation component
*/
protected ValidationComponent createFieldMappingComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String fieldName = field.getName();
MappingClassElement mappingClass =
getMappingClass(getClassName());
if ((mappingClass != null) &&
(mappingClass.getTables().size() > 0))
{
MappingFieldElement mappingField =
mappingClass.getField(fieldName);
if ((mappingField == null) ||
(mappingField.getColumns().size() == 0))
{
throw constructFieldException(
ModelValidationException.WARNING, fieldName,
"util.validation.field_not_mapped"); //NOI18N
}
}
}
};
}
/** Create a validation component which can check whether the field is
* mapped to a blob type and if so, whether it is a key field or belongs
* to the default fetch group. Note that it's somewhat important to check
* for the key field first because if a field is key, its fetch group
* value in the model is ignored.
* @param field the field whose mapping/key field/fetch group consistency
* is being checked
* @return the validation component
*/
protected ValidationComponent createFieldBlobMappingComponent (
final PersistenceFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String className = getClassName();
String fieldName = field.getName();
MappingClassElement mappingClass = getMappingClass(className);
MappingFieldElement mappingField = ((mappingClass != null) ?
mappingClass.getField(fieldName) : null);
if (mappingField != null)
{
boolean isKey = field.isKey();
if (isKey || (MappingFieldElement.GROUP_DEFAULT ==
mappingField.getFetchGroup()))
{
if (isMappedToBlob(mappingField,
getSchemaForClass(className)))
{
throw constructFieldException(fieldName, (isKey ?
"util.validation.field_key_field_not_allowed" : //NOI18N
"util.validation.field_fetch_group_not_allowed")); // NOI18N
}
}
}
}
private boolean isMappedToBlob (MappingFieldElement mappingField,
String schema)
{
if (mappingField instanceof MappingRelationshipElement)
{
return isMappedToBlob(
(MappingRelationshipElement)mappingField, schema);
}
else
{
Iterator iterator = mappingField.getColumns().iterator();
while (iterator.hasNext())
{
String absoluteName = NameUtil.getAbsoluteMemberName(
schema, (String)iterator.next());
TableElement table = TableElement.forName(
NameUtil.getTableName(absoluteName));
ColumnElement columnElement = ((table != null) ?
(ColumnElement)table.getMember(
DBIdentifier.create(absoluteName)) : null);
if (isMappedToBlob(columnElement))
return true;
}
}
return false;
}
private boolean isMappedToBlob (MappingRelationshipElement rel,
String schema)
{
Iterator iterator = rel.getColumns().iterator();
while (iterator.hasNext())
{
ColumnPairElement pair =
getPair((String)iterator.next(), schema);
if (isMappedToBlob(pair))
return true;
}
// now check join columns
iterator = rel.getAssociatedColumns().iterator();
while (iterator.hasNext())
{
ColumnPairElement pair =
getPair((String)iterator.next(), schema);
if (isMappedToBlob(pair))
return true;
}
return false;
}
private boolean isMappedToBlob (ColumnPairElement pair)
{
return ((pair == null) ? false :
isMappedToBlob(pair.getLocalColumn()) &&
isMappedToBlob(pair.getReferencedColumn()));
}
private boolean isMappedToBlob (ColumnElement column)
{
return ((column != null) &&
SQLTypeUtil.isBlob(column.getType()));
}
};
}
/** Create a validation component which can check whether the collection
* class is valid given the relationship field type.
* @param field the relationship whose collection class is being checked
* @return the validation component
*/
protected ValidationComponent createCollectionClassComponent (
final RelationshipElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String className = getClassName();
String fieldName = field.getName();
if (isCollection(className, fieldName))
{
Model model = getModel();
String collectionClass = field.getCollectionClass();
String fieldType = model.getFieldType(className, fieldName);
boolean missingCollectionClass =
StringHelper.isEmpty(collectionClass);
if (!missingCollectionClass &&
!model.getSupportedCollectionClasses(fieldType).
contains(collectionClass))
{
throw constructFieldException(fieldName,
"util.validation.collection_class_invalid");//NOI18N
}
}
}
};
}
/** Create a validation component which can check whether the
* relationship is mapped to columns even though the element class is null.
* @param field the relationship whose element class is being checked
* @return the validation component
*/
protected ValidationComponent createElementClassComponent (
final RelationshipElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String className = getClassName();
String fieldName = field.getName();
if (isCollection(className, fieldName))
{
String elementClass = field.getElementClass();
if (StringHelper.isEmpty(elementClass))
{
MappingClassElement mappingClass =
getMappingClass(className);
MappingFieldElement mappingElement =
((mappingClass != null) ?
mappingClass.getField(fieldName) : null);
if ((mappingElement != null) &&
(mappingElement.getColumns().size() > 0))
{
throw constructFieldException(fieldName,
"util.validation.element_class_not_found");//NOI18N
}
}
}
}
};
}
/** Create a validation component which checks whether the rules for
* version consistency are followed. This includes:
*
* - There must be exactly one version field defined.
*
- The version field must not be a relationship.
*
- The version field must not be a key field.
*
- The version field must be of java type (primitive) long.
*
- The version field must be in the default fetch group.
*
- The version field must be mapped to exactly 1 column from the
* primary table.
*
- The column to which the version field is mapped must be of a
* numeric type and non-nullable.
*
- The column to which the version field is mapped must not be a PK or
* FK column.
*
* @param mappingClass the mapping class element whose consistency is being
* checked
* @return the validation component
*/
protected ValidationComponent createVersionConsistencyComponent (
final MappingClassElement mappingClass)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
// only bother to check for classes with version consistency
if (MappingClassElement.VERSION_CONSISTENCY ==
mappingClass.getConsistencyLevel())
{
MappingFieldElement versionField =
validateVersionFieldExistence();
String className = mappingClass.getName();
String fieldName = versionField.getName();
String columnName = null;
ColumnElement column = null;
if (versionField instanceof MappingRelationshipElement)
{
throw constructFieldException(fieldName,
"util.validation.version_field_relationship_not_allowed");//NOI18N
}
else if (MappingFieldElement.GROUP_DEFAULT !=
versionField.getFetchGroup()) // must be in DFG
{
throw constructFieldException(fieldName,
"util.validation.version_field_fetch_group_invalid");//NOI18N
}
validatePersistenceFieldAttributes(className, fieldName);
columnName = validateVersionFieldMapping(versionField);
column = validateTableMatch(className, fieldName, columnName);
validateColumnAttributes(className, fieldName, column);
}
}
/** Helper method validating the existence of the exactly one
* version field.
*/
private MappingFieldElement validateVersionFieldExistence ()
throws ModelValidationException
{
List versionFields = mappingClass.getVersionFields();
// must have exactly 1 version field (for this release)
if (versionFields.size() != 1)
{
throw constructClassException(mappingClass.getName(),
null, "util.validation.version_field_cardinality"); //NOI18N
}
return (MappingFieldElement)versionFields.get(0);
}
/** Helper method validating the attributes of the field in the
* jdo model which corresponds to the version field.
*/
private void validatePersistenceFieldAttributes (String className,
String fieldName) throws ModelValidationException
{
Class fieldType = JavaTypeHelper.getPrimitiveClass(
getModel().getFieldType(className, fieldName));
String keyName = null;
// must not be a key field
if (getPersistenceClass(className).getField(fieldName).isKey())
keyName = "util.validation.version_field_key_field_not_allowed";//NOI18N
else if (Long.TYPE != fieldType) // must be type long
keyName = "util.validation.version_field_type_not_allowed";//NOI18N
if (keyName != null)
throw constructFieldException(fieldName, keyName);
}
/** Helper method validating the column name of the
* version field mapping.
*/
private String validateVersionFieldMapping (
MappingFieldElement versionField)
throws ModelValidationException
{
List columns = versionField.getColumns();
// must be mapped to exactly 1 column (for this release)
if (columns.size() != 1)
{
throw constructFieldException(versionField.getName(),
"util.validation.version_field_not_mapped"); //NOI18N
}
return (String)columns.get(0);
}
/** Helper method validating the column mapping of the version
* field is from the primary table.
*/
private ColumnElement validateTableMatch (String className,
String fieldName, String columnName)
throws ModelValidationException
{
String schema = getSchemaForClass(className);
String absoluteName =
NameUtil.getAbsoluteMemberName(schema, columnName);
TableElement table =
TableElement.forName(NameUtil.getTableName(absoluteName));
String primaryName = ((MappingTableElement)mappingClass.
getTables().get(0)).getName();
TableElement pTable = getTable(primaryName, schema);
// column must be from the PT
if (table != pTable)
{
throw new ModelValidationException(
getModel().getField(className, fieldName),
I18NHelper.getMessage(getMessages(),
"util.validation.version_field_table_mismatch", //NOI18N
new Object[]{columnName, fieldName, className}));
}
return ((table != null) ? (ColumnElement)table.getMember(
DBIdentifier.create(absoluteName)) : null);
}
/** Helper method validating the attributes of the column of the
* version field mapping.
*/
private void validateColumnAttributes (String className,
String fieldName, ColumnElement column)
throws ModelValidationException
{
String keyName = null;
// column must be numeric type and non-nullable
if (column.isNullable() || !column.isNumericType())
keyName = "util.validation.version_field_column_type_invalid"; // NOI18N
else // column must be non-PK and non-FK column
{
TableElement table = column.getDeclaringTable();
UniqueKeyElement[] uks = table.getUniqueKeys();
ForeignKeyElement[] fks = table.getForeignKeys();
int i, count = ((uks != null) ? uks.length : 0);
for (i = 0; i < count; i++)
{
UniqueKeyElement uk = uks[i];
if (uk.isPrimaryKey() && Arrays.asList(
uk.getColumns()).contains(column))
{
keyName = "util.validation.version_field_column_pk_invalid"; // NOI18N
break;
}
}
count = ((fks != null) ? fks.length : 0);
for (i = 0; i < count; i++)
{
ForeignKeyElement fk = fks[i];
if (Arrays.asList(fk.getLocalColumns()).
contains(column))
{
keyName = "util.validation.version_field_column_fk_invalid"; // NOI18N
break;
}
}
}
if (keyName != null)
{
throw new ModelValidationException(
getModel().getField(className, fieldName),
I18NHelper.getMessage(getMessages(), keyName,
new Object[]{column.getName(), fieldName, className}));
}
}
};
}
/** Create a validation component which can check whether the inverse of
* the inverse of the relationship is the relationship itself.
* @param field the relationship whose inverse relationship is being checked
* @return the validation component
*/
protected ValidationComponent createInverseFieldComponent (
final RelationshipElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
Model model = getModel();
RelationshipElement inverse =
field.getInverseRelationship(model);
RelationshipElement inverseInverse = ((inverse != null) ?
inverse.getInverseRelationship(model) : null);
if ((inverse != null) &&
(!field.equals(inverseInverse) || (inverseInverse == null)))
{
String fieldName = field.getName();
throw new ModelValidationException(
model.getField(getClassName(), fieldName),
I18NHelper.getMessage(getMessages(),
"util.validation.inverse_field_invalid", //NOI18N
new Object[]{fieldName, inverse.getName()}));
}
}
};
}
/** Create a validation component which can check whether the inverse of
* the relationship belongs to the related class (type or element class
* depending on cardinality).
* @param field the relationship whose inverse relationship is being checked
* @return the validation component
*/
protected ValidationComponent createRelatedClassMatchesComponent (
final RelationshipElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String inverseName =
field.getInverseRelationshipName();
if (!StringHelper.isEmpty(inverseName))
{
Model model = getModel();
RelationshipElement inverse =
field.getInverseRelationship(model);
if (inverse == null) // no such field in that related class
{
String relatedClass = getRelatedClass(field);
String fieldName = field.getName();
String key = ((relatedClass != null) ?
"util.validation.related_class_mismatch" : //NOI18N
"util.validation.related_class_not_found");//NOI18N
Object[] args = ((relatedClass != null) ?
new Object[]{fieldName, inverseName, relatedClass}
: new Object[]{fieldName, inverseName});
throw new ModelValidationException(
model.getField(getClassName(), fieldName),
I18NHelper.getMessage(getMessages(), key, args));
}
}
}
};
}
/** Create a validation component which can check whether the mapping of
* the relationship and the mapping of its inverse are inverses of each
* other.
* @param field the relationship whose inverse relationship is being checked
* @return the validation component
*/
protected ValidationComponent createInverseMappingComponent (
final RelationshipElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
Model model = getModel();
RelationshipElement inverse =
field.getInverseRelationship(model);
if ((inverse != null) && !isInverseMapping(field, inverse))
{
String fieldName = field.getName();
throw new ModelValidationException(
model.getField(getClassName(), fieldName),
I18NHelper.getMessage(getMessages(),
"util.validation.inverse_mapping_mismatch", //NOI18N
new Object[]{fieldName, inverse.getName()}));
}
}
private boolean hasMappingRows (MappingRelationshipElement field2)
{
if (field2 != null)
{
ArrayList columns = field2.getColumns();
return ((columns != null) && !columns.isEmpty());
}
return false;
}
private boolean isInverseMapping (RelationshipElement jdoField1,
RelationshipElement jdoField2)
{
MappingRelationshipElement field1 =
getMappingRelationship(jdoField1);
MappingRelationshipElement field2 =
getMappingRelationship(jdoField2);
boolean field1HasMapping = hasMappingRows(field1);
boolean field2HasMapping = hasMappingRows(field2);
// if both have rows, they must be exact inverses
if (field1HasMapping && field2HasMapping)
{
boolean field1IsJoin = isJoin(field1);
if (field1IsJoin == isJoin(field2))
{
ArrayList pairs1 = field1.getColumns();
ArrayList pairs2 = field2.getColumns();
return ((!field1IsJoin) ? isInverse(pairs1, pairs2) :
(isInverse(pairs1,
field2.getAssociatedColumns()) &&
isInverse(field1.getAssociatedColumns(), pairs2)));
}
return false;
}
// if neither have rows that's fine
return (field1HasMapping == field2HasMapping);
}
private boolean isInverse (ArrayList pairs1, ArrayList pairs2)
{
int i, size1 = pairs1.size(), size2 = pairs2.size();
if (size1 == size2)
{
for (i = 0; i < size1; i++)
{
String nextPair = (String)pairs1.get(i);
String inversePair = (String)pairs2.get(i);
int semicolonIndex1 = nextPair.indexOf(';');
int semicolonIndex2 = inversePair.indexOf(';');
if (((semicolonIndex1 == -1) || (semicolonIndex2 == -1))
|| (!nextPair.substring(0, semicolonIndex1).equals(
inversePair.substring(semicolonIndex2 + 1)) ||
!nextPair.substring(semicolonIndex1 + 1).equals(
inversePair.substring(0, semicolonIndex2))))
{
return false;
}
}
return true;
}
return false;
}
};
}
/** Create a validation component which can check whether the field is
* part of a managed (multiple fields to same column) group and in an
* illegal fetch group. If the field is in one of these groups, it is
* not allowed to be in the default fetch group.
* @param field the field whose fetch group is being checked
* @return the validation component
*/
protected ValidationComponent createFieldDefaultFetchGroupComponent (
final MappingFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (field != null)
{
String fieldName = field.getName();
PersistenceClassElement persistenceClass =
getPersistenceClass(getClassName());
PersistenceFieldElement pElement =
((persistenceClass != null) ?
persistenceClass.getField(fieldName) : null);
if ((pElement != null) && !pElement.isKey() &&
(MappingFieldElement.GROUP_DEFAULT ==
field.getFetchGroup()))
{
MappingClassElement mappingClass =
field.getDeclaringClass();
boolean isVersionField =
((MappingClassElement.VERSION_CONSISTENCY ==
mappingClass.getConsistencyLevel()) &&
field.isVersion());
Iterator iterator = mappingClass.getFields().iterator();
String exceptionKey = (!isVersionField ?
"util.validation.field_fetch_group_invalid"://NOI18N
"util.validation.version_field_column_invalid");//NOI18N
/* rules:
* primitive, primitive -> error if exact match of
* columns
* primitive, relationship OR
* relationship, primitive -> error if non-collection
* relationship and none of the relationship's
* columns are PK columns and any are present in
* the primitive's list
* relationship, relationship -> error if exact
* match of mapping (local, join, associated),
* but order is not important
*/
while (iterator.hasNext())
{
MappingFieldElement testField =
(MappingFieldElement)iterator.next();
if (isManaged(field, testField) ||
isManaged(testField, field))
{
throw constructFieldException(
fieldName, exceptionKey);
}
else if (!testField.equals(field) && isExactMatch(
field, testField))
{
throw constructFieldException(
fieldName, exceptionKey);
}
}
}
}
}
private boolean isManaged (MappingFieldElement primField,
MappingFieldElement relField)
{
String className = getClassName();
if (!isRelationship(primField) && isRelationship(relField) &&
!isCollection(className, relField.getName()))
{
ArrayList columns = primField.getColumns();
Iterator iterator = relField.getColumns().iterator();
String databaseRoot = getSchemaForClass(className);
while (iterator.hasNext())
{
if (!testColumn(getLocalColumn((String)iterator.next(),
databaseRoot), columns))
{
return true;
}
}
}
return false;
}
private boolean testColumn (ColumnElement column,
ArrayList masterList)
{
if ((column != null) && !isPrimaryKeyColumn(column))
{
return !masterList.contains(NameUtil.
getRelativeMemberName(column.getName().getFullName()));
}
return true;
}
private ColumnElement getLocalColumn (String pairName,
String databaseRoot)
{
ColumnPairElement pair = getPair(pairName, databaseRoot);
return ((pair != null) ? pair.getLocalColumn() : null);
}
private boolean isPrimaryKeyColumn (ColumnElement column)
{
if (column != null)
{
KeyElement key = column.getDeclaringTable().getPrimaryKey();
return ((key != null) &&
(key.getColumn(column.getName()) != null));
}
return false;
}
private boolean isExactMatch (ArrayList columns1,
ArrayList columns2)
{
int count = columns1.size();
if ((count > 0) && (count == columns2.size()))
return getDifference(columns1, columns2).isEmpty();
return false;
}
private boolean isExactMatch (MappingFieldElement field1,
MappingFieldElement field2)
{
boolean field1IsRel = isRelationship(field1);
boolean match = false;
// both primitives, or both relationships
if (field1IsRel == isRelationship(field2))
{
match = isExactMatch(field1.getColumns(),
field2.getColumns());
if (match && field1IsRel)
{
MappingRelationshipElement rel1 =
(MappingRelationshipElement)field1;
MappingRelationshipElement rel2 =
(MappingRelationshipElement)field2;
boolean field1IsJoin = isJoin(rel1);
// both join relationships or both direct
if (field1IsJoin == isJoin(rel2))
{
if (field1IsJoin)
{
match = isExactMatch(
rel1.getAssociatedColumns(),
rel2.getAssociatedColumns());
}
}
else
match = false;
}
}
return match;
}
};
}
/** Create a validation component which can check whether the schema of
* the related class matches that of the class we are checking.
* @param relatedClass the class whose schema is being checked
* @param relatedField the relationship field whose schema is being
* compared
* @return the validation component
*/
protected ValidationComponent createRelatedSchemaMatchesComponent (
final String relatedClass, final PersistenceFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (relatedClass != null)
{
String className = getClassName();
String mySchema = getSchemaForClass(className);
String relatedSchema = getSchemaForClass(relatedClass);
if ((mySchema != null) && (relatedSchema != null) &&
!(relatedSchema.equals(mySchema)))
{
String fieldName = relatedField.getName();
throw new ModelValidationException(
getModel().getField(className, fieldName),
I18NHelper.getMessage(getMessages(),
"util.validation.schema_mismatch", //NOI18N
new Object[]{className, relatedClass, fieldName}));
}
}
}
};
}
/** Create a validation component which can check whether any of
* the supplied tables of the related class (which includes primary
* and secondary tables) contains the table of the column stored in
* the relationship definition.
* @param relatedClass the class whose table is being checked
* @param relatedField the relationship field whose table is being compared
* @param tableNames the list of names of the tables we expect the
* column to match
* @param pairName the name of the pair whose reference column is to
* be checked
* @return the validation component
*/
protected ValidationComponent createRelatedTableMatchesComponent (
final String relatedClass, final PersistenceFieldElement relatedField,
final List tableNames, final String pairName)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
ColumnPairElement pair = getPair(pairName,
getSchemaForClass(relatedClass));
if (pair != null)
{
ColumnElement column = pair.getReferencedColumn();
if (!matchesTable(tableNames, column))
{
String fieldName = relatedField.getName();
throw new ModelValidationException(
getModel().getField(getClassName(), fieldName),
I18NHelper.getMessage(getMessages(),
getKey(
"util.validation.table_mismatch", //NOI18N
relatedField),
new Object[]{column.getName().getFullName(),
fieldName, relatedClass}));
}
}
}
};
}
/** Create a validation component which can check whether the schema of
* the given class exists.
* @param className the class whose mapped schema's existence is
* being checked
* @return the validation component
*/
protected ValidationComponent createSchemaExistenceComponent (
final String className)
{
return createSchemaExistenceComponent(className, null);
}
/** Create a validation component which can check whether the schema of
* the given class exists.
* @param className the class whose mapped schema's existence is
* being checked
* @param relatedField the relationship field whose class'
* mapped schema is being checked, may be null
in which
* case we are probably checking the same class as the validator is
* checking overall
* @return the validation component
*/
protected ValidationComponent createSchemaExistenceComponent (
final String className, final PersistenceFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String schemaName = getSchemaForClass(className);
if ((schemaName != null) &&
(SchemaElement.forName(schemaName) == null))
{
Object[] args = (relatedField == null) ?
new Object[]{schemaName, className} :
new Object[]{schemaName, className, relatedField};
throw new ModelValidationException(
ModelValidationException.WARNING,
getOffendingObject(relatedField),
I18NHelper.getMessage(getMessages(), getKey(
"util.validation.schema_not_found", //NOI18N
relatedField), args));
}
}
};
}
/** Create a validation component which can check whether the
* class is mapped to tables even though the schema is null or the
* class is mapped to a primary table without a primary key.
* @param primaryTable the primary table for the class
* @return the validation component
*/
protected ValidationComponent createPrimaryTableComponent (
final MappingTableElement primaryTable)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (primaryTable != null)
{
String className = getClassName();
String schemaName = getSchemaForClass(className);
if (schemaName == null)
{
throw constructClassException(className, null,
"util.validation.schema_not_set"); //NOI18N
}
else
{
String tableName = primaryTable.getName();
TableElement table = getTable(tableName, schemaName);
if ((table != null) && (table.getPrimaryKey() == null))
{
throw new ModelValidationException(
getOffendingObject(null),
I18NHelper.getMessage(getMessages(),
"util.validation.table_no_primarykey", //NOI18N
new Object[]{tableName, className}));
}
}
}
}
};
}
/** Create a validation component which can check whether the given table
* exists.
* @param tableName the table whose existence is being checked
* @return the validation component
*/
protected ValidationComponent createTableExistenceComponent (
final String tableName)
{
return createTableExistenceComponent(tableName, null);
}
/** Create a validation component which can check whether the given table
* exists.
* @param tableName the table whose existence is being checked
* @param relatedField the relationship field whose class'
* table is being checked, may be null
in which
* case we are probably checking the same class as the validator is
* checking overall
* @return the validation component
*/
protected ValidationComponent createTableExistenceComponent (
final String tableName, final PersistenceFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (tableName != null)
{
String className = getClassName();
boolean noRelated = (relatedField == null);
TableElement table = getTable(tableName,
getSchemaForClass((noRelated ? className :
getRelatedClass(relatedField))));
if (table == null)
{
Object[] args = noRelated ?
new Object[]{tableName, className} :
new Object[]{tableName, relatedField};
throw new ModelValidationException(
ModelValidationException.WARNING,
getOffendingObject(relatedField),
I18NHelper.getMessage(getMessages(), getKey(
"util.validation.table_not_found", //NOI18N
relatedField), args));
}
}
}
};
}
/** Create a validation component which can check whether the given column
* exists.
* @param columnName the column whose existence is being checked
* @return the validation component
*/
protected ValidationComponent createColumnExistenceComponent (
final String columnName)
{
return createColumnExistenceComponent(columnName, null);
}
/** Create a validation component which can check whether the given
* column or column pair exists.
* @param columnName the column or pair whose existence is being checked
* @param relatedField the field whose class' column is being checked,
* may be null
in which case we are probably checking the
* same secondary table setup
* @return the validation component
*/
protected ValidationComponent createColumnExistenceComponent (
final String columnName, final MappingFieldElement relatedField)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
if (columnName != null)
{
String className = getClassName();
String absoluteName = NameUtil.getAbsoluteMemberName(
getSchemaForClass(className), columnName);
TableElement table = TableElement.forName(
NameUtil.getTableName(absoluteName));
boolean foundTable = (table != null);
DBMemberElement columnElement = ((foundTable) ?
table.getMember(DBIdentifier.create(absoluteName)) :
null);
boolean noRelated = (relatedField == null);
if (foundTable)
{
boolean isRelationship =
(!noRelated && isRelationship(relatedField));
boolean noColumn = (columnElement == null);
if (!isRelationship && noColumn)
{
Object[] args = (noRelated) ?
new Object[]{columnName, className} :
new Object[]{columnName, relatedField,
className};
throw new ModelValidationException(
ModelValidationException.WARNING,
getOffendingObject(relatedField),
I18NHelper.getMessage(getMessages(), getKey(
"util.validation.column_not_found", //NOI18N
relatedField), args));
}
else if (isRelationship &&
(noColumn || !isPairComplete(columnElement)))
{
throw new ModelValidationException(
ModelValidationException.WARNING,
getOffendingObject(relatedField),
I18NHelper.getMessage(getMessages(),
"util.validation.column_invalid", //NOI18N
new Object[]{columnName, relatedField,
className}));
}
}
}
}
private boolean isPairComplete (DBMemberElement member)
{
return ((member instanceof ColumnPairElement) &&
(((ColumnPairElement)member).getLocalColumn() != null) &&
(((ColumnPairElement)member).getReferencedColumn()
!= null));
}
};
}
/** Create a validation component which can check whether the field is
* one of a set mapped to overlapping columns
* @param field the field whose column mapping is being checked
* @return the validation component
*/
protected ValidationComponent createColumnOverlapComponent (
final MappingFieldElement field)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
MappingClassElement mappingClass = field.getDeclaringClass();
Iterator iterator = mappingClass.getFields().iterator();
ArrayList myColumns = field.getColumns();
while (iterator.hasNext())
{
MappingFieldElement testField =
(MappingFieldElement)iterator.next();
if (!testField.equals(field) && !isRelationship(testField)
&& isPartialMatch(myColumns, testField.getColumns()))
{
String fieldName = field.getName();
throw new ModelValidationException(getModel().getField(
getClassName(), fieldName),
I18NHelper.getMessage(getMessages(),
"util.validation.field_mapping_invalid", //NOI18N
new Object[]{fieldName, testField.getName()}));
}
}
}
private boolean isPartialMatch (ArrayList columns1,
ArrayList columns2)
{
int count = columns1.size();
if (count > 0)
{
ArrayList difference = getDifference(columns1, columns2);
return (!difference.isEmpty() &&
(columns2.size() != difference.size()));
}
return false;
}
};
}
/** Create a validation component which can check whether the key class
* of the persistence capable class is valid. This includes:
*
* - The key class must be public.
*
- The key class must implement Serializable.
*
- If the key class is an inner class, it must be static.
*
- The key class must have a public constructor, which might be
* the default constructor or a no-arg constructor.
*
- The field types of all non-static fields in the key class must be
* of valid types.
*
- All serializable non-static fields in the key class must be public.
*
- The names of the non-static fields in the key class must include the
* names of the primary key fields in the JDO class, and the types of the
* common fields must be identical
*
- The key class must redefine equals and hashCode.
*
*/
protected ValidationComponent createKeyClassComponent (
final String className)
{
return new ValidationComponent ()
{
/** The class element of the key class */
private Object keyClass;
/** The fully qualified name of the key class */
private String keyClassName;
public void validate () throws ModelValidationException
{
// checks the key class name
keyClassName = validateKeyClassName(className);
// initilialize keyClass field
keyClass = getModel().getClass(keyClassName, getClassLoader());
validateClass();
validateConstructor();
validateFields();
validateMethods();
}
/** Helper method validating the key class itself:
* public, serializable, static.
*/
private void validateClass () throws ModelValidationException
{
Model model = getModel();
int modifiers = model.getModifiersForClass(keyClassName);
boolean hasKeyClassName = !StringHelper.isEmpty(keyClassName);
boolean isInnerClass =
(hasKeyClassName && (keyClassName.indexOf('$') != -1));
String pcClassName = getClassName();
// check for key class existence
if (keyClass == null)
{
throw new ModelValidationException(
ModelValidationException.WARNING,
model.getClass(pcClassName),
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_missing", //NOI18N
keyClassName, pcClassName));
}
// check for public class modifier
if (!Modifier.isPublic(modifiers))
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_public", //NOI18N
keyClassName, pcClassName));
}
// check for Serializable
/* This check is disabled because of Boston backward
compatibility. In Boston there was no requirement for a
key class being serializable, thus key classes from pc
classes mapped with boston are not serializable.
if (!model.implementsInterface(keyClass,
"java.io.Serializable")) //NOI18N
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_serializable", //NOI18N
keyClassName, pcClassName));
}
*/
// if inner class it must be static
if (isInnerClass && !Modifier.isStatic(modifiers))
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_static", //NOI18N
keyClassName, pcClassName));
}
}
/** Helper method validating the fields of the key class.
*/
private void validateFields () throws ModelValidationException
{
String pcClassName = getClassName();
Model model = getModel();
// check for valid typed public non-static fields
List keyClassFieldNames = model.getAllFields(keyClassName);
Map keyFields = getKeyFields();
for (Iterator i = keyClassFieldNames.iterator(); i.hasNext();)
{
String keyClassFieldName = (String)i.next();
Object keyClassField =
getKeyClassField(keyClassName, keyClassFieldName);
int keyClassFieldModifiers =
model.getModifiers(keyClassField);
String keyClassFieldType = model.getType(keyClassField);
Object keyField = keyFields.get(keyClassFieldName);
if (Modifier.isStatic(keyClassFieldModifiers))
// we are not interested in static fields
continue;
if (!model.isValidKeyType(keyClassName, keyClassFieldName))
{
throw new ModelValidationException(keyClassField,
I18NHelper.getMessage(getMessages(),
"util.validation.key_field_type_invalid", //NOI18N
keyClassFieldName, keyClassName));
}
if (!Modifier.isPublic(keyClassFieldModifiers))
{
throw new ModelValidationException(keyClassField,
I18NHelper.getMessage(getMessages(),
"util.validation.key_field_public", //NOI18N
keyClassFieldName, keyClassName));
}
if (keyField == null)
continue;
if (!keyClassFieldType.equals(model.getType(keyField)))
{
throw new ModelValidationException(keyClassField,
I18NHelper.getMessage(getMessages(),
"util.validation.key_field_type_mismatch", //NOI18N
keyClassFieldName, keyClassName, pcClassName));
}
// remove handled keyField from the list of keyFields
keyFields.remove(keyClassFieldName);
}
// check whether there are any unhandled key fields
if (!keyFields.isEmpty())
{
Object pcClass = model.getClass(pcClassName);
String fieldNames = StringHelper.arrayToSeparatedList(
new ArrayList(keyFields.keySet()));
throw new ModelValidationException(pcClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_field_missing", //NOI18N
pcClassName, keyClassName, fieldNames));
}
}
/** Helper method validating the key class constructors.
*/
private void validateConstructor () throws ModelValidationException
{
// no constructor or no arg constructor
Model model = getModel();
boolean hasConstr = model.hasConstructor(keyClassName);
Object noArgConstr =
model.getConstructor(keyClassName, Model.NO_ARGS);
int modifiers = model.getModifiers(noArgConstr);
if (hasConstr &&
((noArgConstr == null) || !Modifier.isPublic(modifiers)))
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_constructor", //NOI18N
keyClassName, getClassName()));
}
}
/** Helper method validating the key class methods.
*/
private void validateMethods () throws ModelValidationException
{
Model model = getModel();
Object equalsMethod = getNonObjectMethod(keyClassName,
"equals", Model.getEqualsArgs()); //NOI18N
Object hashCodeMethod = getNonObjectMethod(keyClassName,
"hashCode", Model.NO_ARGS); //NOI18N
// check equals method
if (!matchesMethod(equalsMethod, Modifier.PUBLIC,
0, "boolean")) //NOI18N
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_equals", //NOI18N
keyClassName, getClassName()));
}
// check hashCode method
if (!matchesMethod(hashCodeMethod, Modifier.PUBLIC,
0, "int")) //NOI18N
{
throw new ModelValidationException(keyClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_hashcode", //NOI18N
keyClassName, getClassName()));
}
}
/** Helper method validating the name of the key class.
*/
private String validateKeyClassName (String keyClassName)
throws ModelValidationException
{
String pcClassName = getClassName();
Model model = getModel();
boolean hasKeyClassName = !StringHelper.isEmpty(keyClassName);
boolean hasPrefix;
String nameSuffix;
boolean isOIDNameSuffix;
// check for existence of key class name
if (!hasKeyClassName)
{
throw new ModelValidationException(
ModelValidationException.WARNING,
model.getClass(pcClassName),
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_unset", //NOI18N
pcClassName));
}
keyClassName = keyClassName.trim();
hasPrefix = keyClassName.startsWith(pcClassName);
nameSuffix = (hasPrefix ?
keyClassName.substring(pcClassName.length()) : keyClassName);
isOIDNameSuffix =
(nameSuffix.equalsIgnoreCase(".OID") || // NOI18N
nameSuffix.equalsIgnoreCase("$OID")); // NOI18N
if (!hasPrefix ||
(!nameSuffix.equalsIgnoreCase("Key") && // NOI18N
!isOIDNameSuffix))
{
Object pcClass = getModel().getClass(pcClassName);
throw new ModelValidationException(pcClass,
I18NHelper.getMessage(getMessages(),
"util.validation.key_class_invalid", //NOI18N
keyClassName, pcClassName));
}
if (isOIDNameSuffix)
{
StringBuilder buf = new StringBuilder(keyClassName);
buf.setCharAt(keyClassName.length() - 4, '$');
return buf.toString();
}
return keyClassName;
}
// helper method which returns a field object from the
// given class or one of its superclasses
private Object getKeyClassField (String keyClassName,
String keyClassFieldName)
{
Model model = getModel();
Object keyClassField =
model.getField(keyClassName, keyClassFieldName);
if (keyClassField == null) // this is an inherited field
{
keyClassField = model.getInheritedField(
keyClassName, keyClassFieldName);
}
return keyClassField;
}
/** Helper method returning the key fields of the pc class as a map.
*/
private Map getKeyFields ()
{
Model model = getModel();
String pcClassName = getClassName();
PersistenceClassElement pce =
model.getPersistenceClass(pcClassName);
PersistenceFieldElement[] fields = pce.getFields();
Map keyFields = new HashMap();
if (fields != null)
{
for (int i = 0; i < fields.length; i++)
{
PersistenceFieldElement pfe = fields[i];
if (pfe.isKey())
{
String name = pfe.getName();
keyFields.put(name,
model.getField(pcClassName, name));
}
}
}
return keyFields;
}
// helper method which returns a method object from the
// given class or one of its superclasses provided it
// is not java.lang.Object
private Object getNonObjectMethod (String className,
String methodName, String[] argTypeNames)
{
Model model = getModel();
Object method =
model.getMethod(className, methodName, argTypeNames);
if (method == null) // look for an inherited method
{
method = model.getInheritedMethod(
className, methodName, argTypeNames);
if ((method != null) && model.getDeclaringClass(method).
equals("java.lang.Object")) // NOI18N
{
method = null;
}
}
return method;
}
};
}
/** Create a validation component which can check that the persistence
* capable class implement methods readObject and writeObject, if the class
* implements the intreface java.io.Serializable
* @param className the class whose methods are checked
* @return the validation component
*/
protected ValidationComponent createSerializableClassComponent (
final String className)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
Model model = getModel();
Object pcClass = null;
if (className == null)
return;
pcClass = model.getClass(className);
if (pcClass == null)
return;
if (model.implementsInterface(pcClass, "java.io.Serializable")) //NOI18N
{
// check readObject method
Object readMethod = model.getMethod(className,
"readObject", Model.getReadObjectArgs()); //NOI18N
if (!matchesMethod(readMethod, Modifier.PRIVATE,
Modifier.SYNCHRONIZED, "void")) // NOI18N
{
throw new ModelValidationException(pcClass,
I18NHelper.getMessage(getMessages(),
"util.validation.class_readobject", //NOI18N
className));
}
// check writeObject method
Object writeMethod = model.getMethod(className,
"writeObject", Model.getWriteObjectArgs()); //NOI18N
if (!matchesMethod(writeMethod, Modifier.PRIVATE,
Modifier.SYNCHRONIZED, "void")) // NOI18N
{
throw new ModelValidationException(pcClass,
I18NHelper.getMessage(getMessages(),
"util.validation.class_writeobject", //NOI18N
className));
}
}
}
};
}
/** Create a validation component which can check whether the class is
* unmapped.
* @param persistenceClass the class whose mapping is being checked
* @return the validation component
*/
protected ValidationComponent createClassMappingComponent (
final PersistenceClassElement persistenceClass)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
PersistenceFieldElement[] fields = persistenceClass.getFields();
String className = getClassName();
if ((fields == null) || fields.length == 0)
{
throw constructClassException(
ModelValidationException.WARNING, className, null,
"util.validation.class_no_fields"); //NOI18N
}
else // has fields, check for primary table
{
MappingClassElement mappingClass =
getMappingClass(className);
if ((mappingClass == null) ||
(mappingClass.getTables().size() == 0))
{
throw constructClassException(
ModelValidationException.WARNING, className, null,
"util.validation.class_not_mapped"); //NOI18N
}
}
}
};
}
/** Create a validation component which can check whether the class
* contains field mappings for all primary key columns.
* @param persistenceClass the class whose mapping is being checked
* @return the validation component
*/
protected ValidationComponent createKeyColumnMappingComponent (
final PersistenceClassElement persistenceClass)
{
return new ValidationComponent ()
{
public void validate () throws ModelValidationException
{
String className = getClassName();
MappingClassElement mappingClass = getMappingClass(className);
if (mappingClass != null)
{
List tables = mappingClass.getTables();
if (tables.size() > 0)
{
String tableName =
((MappingTableElement)tables.get(0)).getName();
TableElement table = getTable(tableName,
getSchemaForClass(className));
List columns = getUnmappedColumnNames(
((table != null) ? table.getPrimaryKey() : null),
mappingClass);
if ((columns != null) && (columns.size() > 0))
{
throw new ModelValidationException(
ModelValidationException.WARNING,
getOffendingObject(null),
I18NHelper.getMessage(getMessages(),
"util.validation.class_key_column_missing", //NOI18N
className, tableName,
StringHelper.arrayToSeparatedList(columns)));
}
}
}
}
private List getUnmappedColumnNames (KeyElement primaryKey,
MappingClassElement mappingClass)
{
List unmappedColumns = null;
if (primaryKey != null) // check if primary table has a pk
{
ColumnElement[] columns = primaryKey.getColumns();
int count = ((columns != null) ? columns.length : 0);
// all columns in the pk should be mapped to key fields
if (count > 0)
{
List mappingFields = mappingClass.getFields();
Iterator iterator = mappingFields.iterator();
unmappedColumns = getRelativeColumnNames(columns);
while (iterator.hasNext())
{
MappingFieldElement field =
(MappingFieldElement)iterator.next();
if (isKeyField(field))
unmappedColumns.removeAll(field.getColumns());
}
}
}
return unmappedColumns;
}
private List getRelativeColumnNames (ColumnElement[] columns)
{
int i, count = ((columns != null) ? columns.length : 0);
List columnNames = new ArrayList(count);
for (i = 0; i < count; i++)
{
columnNames.add(NameUtil.getRelativeMemberName(
columns[i].getName().getFullName()));
}
return columnNames;
}
private boolean isKeyField (MappingFieldElement field)
{
PersistenceFieldElement persistenceField =
persistenceClass.getField(field.getName());
return ((persistenceField != null) && persistenceField.isKey());
}
};
}
//========== Convenience methods for exception construction ============
/** Computes the offending object to be used in the construction of a
* ModelValidationException as follows: if a non-null field is supplied,
* the corresponding org.openide.src.FieldElement is returned, otherwise,
* corresponding org.openide.src.ClassElement is returned.
* @param field the field object which caused the problem - may be
* null
* @return the offending object
*/
private Object getOffendingObject (Object field)
{
return ((field == null) ?
getModel().getClass(getClassName(), getClassLoader()) :
getModel().getField(getClassName(), field.toString()));
}
/** Computes the key for the i18n string to be used in the construction
* of a ModelValidationException as follows: if a non-null field is
* supplied, "_related" is appending to the supplied key base, otherwise,
* the key base is returned as is.
* @param keyBase the base key to be used for the i18n string
* @param field the field object which caused the problem - may be
* null
* @return the key
*/
private String getKey (String keyBase, Object field)
{
return ((field == null) ? keyBase : (keyBase + "_related")); //NOI18N
}
/** Computes the arguments for the i18n string to be used in the
* construction of a ModelValidationException as follows: if a
* non-null field is supplied, an array containing the supplied className
* and field is returned, otherwise, an array containing only the supplied
* className is returned.
* @param className the name of the class which caused the problem
* @param field the field object which caused the problem - may be
* null
* @return the argument array
*/
private Object[] getArguments (String className, Object field)
{
return ((field == null) ? new Object[]{className} :
new Object[]{className, field});
}
/** Constructs a ModelValidationException for class validation tests
* using the supplied class name, related field, and key base.
* @param className the name of the class which caused the problem
* @param field the field object which caused the problem - may be
* null
* @param keyBase the base key to be used for the i18n string
* @return the ModelValidationException
* @see #getOffendingObject
* @see #getKey
* @see #getArguments
* @see #constructFieldException
*/
private ModelValidationException constructClassException (String className,
Object relatedField, String keyBase)
{
return constructClassException(ModelValidationException.ERROR,
className, relatedField, keyBase);
}
/** Constructs a ModelValidationException for class validation tests
* using the supplied class name, related field, and key base.
* @param errorType the type of error -- one of
* {@link ModelValidationException#ERROR} or
* {@link ModelValidationException#WARNING}.
* @param className the name of the class which caused the problem
* @param field the field object which caused the problem - may be
* null
* @param keyBase the base key to be used for the i18n string
* @return the ModelValidationException
* @see #getOffendingObject
* @see #getKey
* @see #getArguments
* @see #constructFieldException
*/
private ModelValidationException constructClassException (int errorType,
String className, Object relatedField, String keyBase)
{
return new ModelValidationException(errorType,
getOffendingObject(relatedField), I18NHelper.getMessage(
getMessages(), getKey(keyBase, relatedField),
getArguments(className, relatedField)));
}
/** Constructs a ModelValidationException for field validation tests
* using the supplied field name and key.
* @param fieldName the name of the field which caused the problem
* @param keyBase the base key to be used for the i18n string
* @return the ModelValidationException
* @see #constructClassException
*/
private ModelValidationException constructFieldException (String fieldName,
String key)
{
return constructFieldException(ModelValidationException.ERROR,
fieldName, key);
}
/** Constructs a ModelValidationException for field validation tests
* using the supplied field name and key.
* @param errorType the type of error -- one of
* {@link ModelValidationException#ERROR} or
* {@link ModelValidationException#WARNING}.
* @param fieldName the name of the field which caused the problem
* @param keyBase the base key to be used for the i18n string
* @return the ModelValidationException
* @see #constructClassException
*/
private ModelValidationException constructFieldException (int errorType,
String fieldName, String key)
{
return new ModelValidationException(errorType,
getModel().getField(getClassName(), fieldName),
I18NHelper.getMessage(getMessages(), key, fieldName));
}
//=============== Misc. private convenience methods ================
/** Checks whether the specified method element exists and if so whether it
* has the expected modifiers and the expected return type.
* @param method the method element to be checked
* @param expectedModifiers the modifiers the method should have
* @param optionalModifiers additional modifiers the method might have
* @param expectedReturnType the return type the method should have
* @return true
if the method matches,
* false
otherwise.
*/
private boolean matchesMethod (final Object method,
final int expectedModifiers, final int optionalModifiers,
final String expectedReturnType)
{
boolean matches = false;
if (method != null)
{
Model model = getModel();
int modifiers = model.getModifiers(method);
matches = (((modifiers == expectedModifiers) ||
(modifiers == (expectedModifiers | optionalModifiers))) &&
expectedReturnType.equals(model.getType(method)));
}
return matches;
}
/** Check if the table of the column matches one of the list of tables.
* @param tableNames A list of table names in which to check for a match
* @param column A ColumnElement object to be checked
* @return true
if the column belongs to a table found
* in the supplied list of table names, false
otherwise
*/
private boolean matchesTable (List tableNames, ColumnElement column)
{
return ((column == null) ? true : tableNames.contains(
column.getDeclaringTable().getName().getName()));
}
private boolean isRelationship (Object field)
{
return ((field instanceof RelationshipElement) ||
(field instanceof MappingRelationshipElement));
}
private boolean shouldBeRelationship (PersistenceFieldElement field)
{
Model model = getModel();
String fieldType = model.getFieldType(getClassName(), field.getName());
return (isPersistent(fieldType) || model.isCollection(fieldType));
}
private boolean isLegalRelationship (PersistenceFieldElement field)
{
return (isRelationship(field) ? shouldBeRelationship(field) : false);
}
private boolean isCollection (String className, String fieldName)
{
Model model = getModel();
return model.isCollection(model.getFieldType(className, fieldName));
}
private String getRelatedClass (PersistenceFieldElement field)
{
if (isLegalRelationship(field))
return getModel().getRelatedClass((RelationshipElement)field);
return null;
}
private String getSchemaForClass (String className)
{
MappingClassElement mappingClass = getMappingClass(className);
String schema = ((mappingClass != null) ?
mappingClass.getDatabaseRoot() : null);
return (StringHelper.isEmpty(schema) ? null : schema.trim());
}
private MappingRelationshipElement getMappingRelationship (
RelationshipElement jdoElement)
{
MappingRelationshipElement mappingElement = null;
if (jdoElement != null)
{
MappingClassElement mappingClass = getMappingClass(
jdoElement.getDeclaringClass().getName());
if (mappingClass != null)
{
MappingFieldElement fieldElement =
mappingClass.getField(jdoElement.getName());
if (isRelationship(fieldElement))
mappingElement = (MappingRelationshipElement)fieldElement;
}
}
return mappingElement;
}
private boolean isJoin (MappingRelationshipElement field)
{
if (field != null)
{
ArrayList columns = field.getAssociatedColumns();
return ((columns != null) && !columns.isEmpty());
}
return false;
}
private MappingReferenceKeyElement findReferenceKey (
MappingTableElement primaryTable, MappingTableElement secondaryTable)
{
if ((primaryTable != null) && (secondaryTable != null))
{
Iterator iterator = primaryTable.getReferencingKeys().iterator();
while (iterator.hasNext())
{
MappingReferenceKeyElement testKey =
(MappingReferenceKeyElement)iterator.next();
if (testKey.getTable().equals(secondaryTable))
return testKey;
}
}
return null;
}
private TableElement getTable (String tableName, String databaseRoot)
{
String absoluteName = NameUtil.getAbsoluteTableName(databaseRoot,
tableName);
return TableElement.forName(absoluteName);
}
private ColumnPairElement getPair (String pairName, String databaseRoot)
{
String absoluteName = NameUtil.getAbsoluteMemberName(
databaseRoot, pairName);
TableElement tableElement = TableElement.forName(
NameUtil.getTableName(absoluteName));
DBMemberElement pair = ((tableElement == null) ? null :
tableElement.getMember(DBIdentifier.create(absoluteName)));
return ((pair instanceof ColumnPairElement) ?
((ColumnPairElement)pair) : null);
}
private ArrayList getDifference (ArrayList columns1, ArrayList columns2)
{
ArrayList differenceColumns = new ArrayList(columns2);
differenceColumns.removeAll(columns1);
return differenceColumns;
}
/**
* Convenience method to call Model.getMappingClass.
*/
private MappingClassElement getMappingClass (String className)
{
return getModel().getMappingClass(className, getClassLoader());
}
/**
* Convenience method to call Model.getPersistenceClass.
*/
private PersistenceClassElement getPersistenceClass (String className)
{
return getModel().getPersistenceClass(className, getClassLoader());
}
/**
* Convenience method to call Model.isPersistent
*/
private boolean isPersistent (String className)
{
return getModel().isPersistent(className, getClassLoader());
}
/**
* Convenience method to call Model.isPersistentAllowed
*/
private boolean isPersistentAllowed (String className, String fieldName)
{
return getModel().isPersistentAllowed(className, getClassLoader(),
fieldName);
}
// ================== Validation component support =================
/** Abstraction of component tests for validation.
*/
static abstract class ValidationComponent
{
/** Constructs a new ValidationComponent
*/
public ValidationComponent ()
{
}
/** Method which validates this component
* @exception ModelValidationException when the validation fails.
*/
public abstract void validate () throws ModelValidationException;
}
}