blob: c8db77abef438741efd18e0750d20bbc05d82998 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.jdbc.meta;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.sql.Types;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
import org.apache.openjpa.jdbc.meta.strats.BlobValueHandler;
import org.apache.openjpa.jdbc.meta.strats.ByteArrayValueHandler;
import org.apache.openjpa.jdbc.meta.strats.CharArrayStreamValueHandler;
import org.apache.openjpa.jdbc.meta.strats.CharArrayValueHandler;
import org.apache.openjpa.jdbc.meta.strats.ClassNameDiscriminatorStrategy;
import org.apache.openjpa.jdbc.meta.strats.ClobValueHandler;
import org.apache.openjpa.jdbc.meta.strats.ElementEmbedValueHandler;
import org.apache.openjpa.jdbc.meta.strats.EmbedFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.EmbeddedClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.FlatClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerCollectionTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerHandlerMapTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.HandlerRelationMapTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.ImmutableValueHandler;
import org.apache.openjpa.jdbc.meta.strats.LobFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedBlobFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedByteArrayFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedCharArrayFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MaxEmbeddedClobFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.MultiColumnVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.
NanoPrecisionTimestampVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.NoneDiscriminatorStrategy;
import org.apache.openjpa.jdbc.meta.strats.NoneFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.NoneVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.NumberVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.ObjectIdClassStrategy;
import org.apache.openjpa.jdbc.meta.strats.ObjectIdValueHandler;
import org.apache.openjpa.jdbc.meta.strats.PrimitiveFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.
RelationCollectionInverseKeyFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.RelationCollectionTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.RelationFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.RelationHandlerMapTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.RelationMapInverseKeyFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.RelationMapTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.
RelationRelationMapTableFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.StateComparisonVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.StringFieldStrategy;
import org.apache.openjpa.jdbc.meta.strats.SubclassJoinDiscriminatorStrategy;
import org.apache.openjpa.jdbc.meta.strats.SuperclassDiscriminatorStrategy;
import org.apache.openjpa.jdbc.meta.strats.SuperclassVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.TimestampVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.UntypedPCValueHandler;
import org.apache.openjpa.jdbc.meta.strats.ValueMapDiscriminatorStrategy;
import org.apache.openjpa.jdbc.meta.strats.VerticalClassStrategy;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.SchemaGroup;
import org.apache.openjpa.jdbc.sql.DBDictionary;
import org.apache.openjpa.jdbc.sql.JoinSyntaxes;
import org.apache.openjpa.lib.conf.Configurable;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.meta.Order;
import org.apache.openjpa.meta.SequenceMetaData;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.MetaDataException;
import org.apache.openjpa.util.UserException;
/**
* Repository of object/relational mapping information.
*
* @author Abe White
*/
public class MappingRepository extends MetaDataRepository {
private static final long serialVersionUID = 1L;
private static final Localizer _loc = Localizer.forPackage
(MappingRepository.class);
private transient DBDictionary _dict = null;
private transient MappingDefaults _defaults = null;
// object->queryresultmapping
private Map<Object, QueryResultMapping> _results = new HashMap<>();
private SchemaGroup _schema = null;
private StrategyInstaller _installer = null;
/**
* Default constructor. Configure via
* {@link org.apache.openjpa.lib.conf.Configurable}.
*/
public MappingRepository() {
setValidate(VALIDATE_MAPPING, true);
}
/**
* Convenient access to dictionary for mappings.
*/
public DBDictionary getDBDictionary() {
return _dict;
}
/**
* Mapping defaults.
*/
public MappingDefaults getMappingDefaults() {
return _defaults;
}
/**
* Mapping default.
*/
public void setMappingDefaults(MappingDefaults defaults) {
_defaults = defaults;
}
/**
* Representation of the database schema.
*/
public SchemaGroup getSchemaGroup() {
if (_locking) {
synchronized (this) {
if (_schema == null)
_schema = ((JDBCConfiguration) getConfiguration()).getSchemaFactoryInstance().readSchema();
return _schema;
}
} else {
if (_schema == null)
_schema = ((JDBCConfiguration) getConfiguration()).getSchemaFactoryInstance().readSchema();
return _schema;
}
}
/**
* Representation of the database schema.
*/
public void setSchemaGroup(SchemaGroup schema) {
if (_locking) {
synchronized (this) {
_schema = schema;
}
} else {
_schema = schema;
}
}
/**
* Installs mapping strategies on components.
*/
public StrategyInstaller getStrategyInstaller() {
if (_locking) {
synchronized (this) {
if (_installer == null)
_installer = new RuntimeStrategyInstaller(this);
return _installer;
}
} else {
if (_installer == null)
_installer = new RuntimeStrategyInstaller(this);
return _installer;
}
}
/**
* Installs mapping strategies on components.
*/
public void setStrategyInstaller(StrategyInstaller installer) {
if (_locking) {
synchronized (this) {
_installer = installer;
}
} else {
_installer = installer;
}
}
/**
* Return the query result mapping for the given name.
*/
public QueryResultMapping getQueryResultMapping(Class<?> cls, String name, ClassLoader loader, boolean mustExist) {
QueryResultMapping res;
if (_locking) {
synchronized (this) {
res = getQueryResultMappingInternal(cls, name, loader);
}
} else {
res = getQueryResultMappingInternal(cls, name, loader);
}
if (res == null && mustExist)
throw new MetaDataException(_loc.get("no-query-res", cls, name));
return res;
}
/**
* Returned the query result mapping with the given name.
*/
private QueryResultMapping getQueryResultMappingInternal(Class<?> cls, String name, ClassLoader envLoader) {
if (name == null)
return null;
// check cache
Object key = getQueryResultKey(cls, name);
QueryResultMapping res = _results.get(key);
if (res != null)
return res;
// get metadata for class, which will find results in metadata file
if (cls != null && getMetaData(cls, envLoader, false) != null) {
res = _results.get(key);
if (res != null)
return res;
}
if ((getSourceMode() & MODE_QUERY) == 0)
return null;
if (cls == null)
cls = getMetaDataFactory()
.getResultSetMappingScope(name, envLoader);
// not in cache; load
getMetaDataFactory().load(cls, MODE_META | MODE_MAPPING, envLoader);
return _results.get(key);
}
/**
* Return all cached query result mappings.
*/
public QueryResultMapping[] getQueryResultMappings() {
if (_locking) {
synchronized (this) {
Collection values = _results.values();
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
}
} else {
Collection values = _results.values();
return (QueryResultMapping[]) values.toArray(new QueryResultMapping[values.size()]);
}
}
/**
* Return the cached query result mapping with the given name, or null if
* none.
*/
public QueryResultMapping getCachedQueryResultMapping(Class cls, String name) {
if (_locking) {
synchronized (this) {
return (QueryResultMapping) _results.get(getQueryResultKey(cls, name));
}
} else {
return (QueryResultMapping) _results.get(getQueryResultKey(cls, name));
}
}
/**
* Add a query result mapping.
*/
public QueryResultMapping addQueryResultMapping(Class cls, String name) {
if (_locking) {
synchronized (this) {
return addQueryResultMappingInternal(cls, name);
}
} else {
return addQueryResultMappingInternal(cls, name);
}
}
private QueryResultMapping addQueryResultMappingInternal(Class cls, String name) {
QueryResultMapping res = new QueryResultMapping(name, this);
res.setDefiningType(cls);
_results.put(getQueryResultKey(res), res);
return res;
}
/**
* Remove a query result mapping.
*/
public boolean removeQueryResultMapping(QueryResultMapping res) {
if (_locking) {
synchronized (this) {
return _results.remove(getQueryResultKey(res)) != null;
}
} else {
return _results.remove(getQueryResultKey(res)) != null;
}
}
/**
* Remove a query result mapping.
*/
public boolean removeQueryResultMapping(Class cls, String name) {
if (_locking) {
synchronized (this) {
if (name == null)
return false;
return _results.remove(getQueryResultKey(cls, name)) != null;
}
} else {
if (name == null)
return false;
return _results.remove(getQueryResultKey(cls, name)) != null;
}
}
/**
* Return a unique key for the given mapping.
*/
private static Object getQueryResultKey(QueryResultMapping res) {
if (res == null)
return null;
return getQueryResultKey(res.getDefiningType(), res.getName());
}
/**
* Return a unique key for the given class / name. The class argument
* can be null.
*/
private static Object getQueryResultKey(Class<?> cls, String name) {
return getQueryKey(cls, name);
}
public ClassMapping getMapping(Class<?> cls, ClassLoader envLoader,
boolean mustExist) {
return (ClassMapping) super.getMetaData(cls, envLoader, mustExist);
}
public ClassMapping[] getMappings() {
return (ClassMapping[]) super.getMetaDatas();
}
public ClassMapping getMapping(Object oid, ClassLoader envLoader,
boolean mustExist) {
return (ClassMapping) super.getMetaData(oid, envLoader, mustExist);
}
public ClassMapping[] getImplementorMappings(Class<?> cls,
ClassLoader envLoader, boolean mustExist) {
return (ClassMapping[]) super.getImplementorMetaDatas(cls, envLoader,
mustExist);
}
@Override
public void clear() {
if (_locking) {
synchronized (this) {
super.clear();
_schema = null;
_results.clear();
}
} else {
super.clear();
_schema = null;
_results.clear();
}
}
@Override
protected void prepareMapping(ClassMetaData meta) {
// make sure superclass resolved first; resolving superclass may have
// resolved this mapping
ClassMapping mapping = (ClassMapping) meta;
ClassMapping sup = mapping.getPCSuperclassMapping();
if (sup != null && (mapping.getResolve() & MODE_MAPPING) != 0)
return;
// if this mapping is not for a managed interface, ensure that if
// we have an inheritance hierarchy there is a default strategy
// applied to the root class
if (!mapping.getDescribedType().isInterface() &&
!mapping.isEmbeddedOnly()) {
// if an inheritance strategy has not been set on this mapping
// determine if needs one and if so, set it
if (!hasInheritanceStrategy(mapping)) {
ClassMapping baseMapping = findBaseClassMapping(mapping);
if (baseMapping != null)
setDefaultInheritanceStrategy(baseMapping);
}
}
// define superclass fields after mapping class, so we can tell whether
// the class is mapped and needs to redefine abstract superclass fields
getStrategyInstaller().installStrategy(mapping);
mapping.defineSuperclassFields(mapping.getJoinablePCSuperclassMapping()
== null);
// resolve everything that doesn't involve relations to allow relation
// mappings to use the others as joinables
mapping.resolveNonRelationMappings();
}
@Override
protected ClassMetaData newClassMetaData(Class<?> type) {
return new ClassMapping(type, this);
}
@Override
protected ClassMetaData[] newClassMetaDataArray(int length) {
return new ClassMapping[length];
}
@Override
protected FieldMetaData newFieldMetaData(String name, Class<?> type,
ClassMetaData owner) {
return new FieldMapping(name, type, (ClassMapping) owner);
}
@Override
protected FieldMetaData[] newFieldMetaDataArray(int length) {
return new FieldMapping[length];
}
@Override
protected ClassMetaData newEmbeddedClassMetaData(ValueMetaData owner) {
return new ClassMapping(owner);
}
@Override
protected ValueMetaData newValueMetaData(FieldMetaData owner) {
return new ValueMappingImpl((FieldMapping) owner);
}
@Override
protected SequenceMetaData newSequenceMetaData(String name) {
return new SequenceMapping(name, this);
}
@Override
protected Order newValueOrder(FieldMetaData owner, boolean asc) {
return new JDBCValueOrder((FieldMapping) owner, asc);
}
@Override
protected Order newRelatedFieldOrder(FieldMetaData owner,
FieldMetaData rel, boolean asc) {
return new JDBCRelatedFieldOrder((FieldMapping) owner,
(FieldMapping) rel, asc);
}
@Override
protected Order[] newOrderArray(int size) {
return new JDBCOrder[size];
}
/**
* Create version metadata for the given class.
*/
protected Version newVersion(ClassMapping cls) {
return new Version(cls);
}
/**
* Create discriminator metadata for the given class.
*/
protected Discriminator newDiscriminator(ClassMapping cls) {
return new Discriminator(cls);
}
/**
* Create raw mapping info for the given instance.
*/
protected ClassMappingInfo newMappingInfo(ClassMapping cls) {
ClassMappingInfo info = new ClassMappingInfo();
info.setClassName(cls.getDescribedType().getName());
return info;
}
/**
* Create raw mapping info for the given instance.
*/
protected FieldMappingInfo newMappingInfo(FieldMapping fm) {
return new FieldMappingInfo();
}
/**
* Create raw mapping info for the given instance.
*/
protected ValueMappingInfo newMappingInfo(ValueMapping vm) {
return new ValueMappingInfo();
}
/**
* Create raw mapping info for the given instance.
*/
protected VersionMappingInfo newMappingInfo(Version version) {
return new VersionMappingInfo();
}
/**
* Create raw mapping info for the given instance.
*/
protected DiscriminatorMappingInfo newMappingInfo(Discriminator disc) {
return new DiscriminatorMappingInfo();
}
/**
* Instantiate the given class' named strategy, or return null if no
* named strategy.
*/
protected ClassStrategy namedStrategy(ClassMapping cls) {
String name = cls.getMappingInfo().getStrategy();
return instantiateClassStrategy(name, cls);
}
/**
* Return the strategy for the given name.
*/
protected ClassStrategy instantiateClassStrategy(String name,
ClassMapping cls) {
if (name == null)
return null;
if (NoneClassStrategy.ALIAS.equals(name))
return NoneClassStrategy.getInstance();
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
Class<?> strat = null;
// base and vertical strategies use same alias; differentiate on join
if (FullClassStrategy.ALIAS.equals(name))
strat = FullClassStrategy.class;
else if (FlatClassStrategy.ALIAS.equals(name))
strat = FlatClassStrategy.class;
else if (VerticalClassStrategy.ALIAS.equals(name))
strat = VerticalClassStrategy.class;
try {
if (strat == null)
strat = JavaTypes.classForName(name, cls,
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(
ClassStrategy.class)), false);
ClassStrategy strategy =
(ClassStrategy) AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(strat));
Configurations.configureInstance(strategy, getConfiguration(),
props);
return strategy;
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-cls-strategy",
cls, name), e);
}
}
/**
* Instantiate the given field's named strategy, or return null if no
* named strategy.
*/
protected FieldStrategy namedStrategy(FieldMapping field,
boolean installHandlers) {
String name = field.getMappingInfo().getStrategy();
if (name == null)
return null;
if (NoneFieldStrategy.ALIAS.equals(name))
return NoneFieldStrategy.getInstance();
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
try {
Class<?> c = JavaTypes.classForName(name, field,
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(FieldStrategy.class)), false);
if (FieldStrategy.class.isAssignableFrom(c)) {
FieldStrategy strat = (FieldStrategy)
AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(c));
Configurations.configureInstance(strat, getConfiguration(),
props);
return strat;
}
// must be named handler
if (installHandlers) {
ValueHandler vh = (ValueHandler) AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(c));
Configurations.configureInstance(vh, getConfiguration(),
props);
field.setHandler(vh);
}
return new HandlerFieldStrategy();
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-field-strategy",
field, name), e);
}
}
/**
* Instantiate the given discriminator's named strategy, or return null
* if no named strategy.
*/
protected DiscriminatorStrategy namedStrategy(Discriminator discrim) {
String name = discrim.getMappingInfo().getStrategy();
if (name == null)
return null;
// if there is a named strategy present, discard it if it matches
// the base strategy, so that we won't create an independent instance
ClassMapping cls = discrim.getClassMapping();
while (cls.getJoinablePCSuperclassMapping() != null)
cls = cls.getJoinablePCSuperclassMapping();
Discriminator base = cls.getDiscriminator();
if (base != discrim && base.getStrategy() != null
&& name.equals(base.getStrategy().getAlias()))
return null;
return instantiateDiscriminatorStrategy(name, discrim);
}
/**
* Instantiate the given discriminator strategy.
*/
protected DiscriminatorStrategy instantiateDiscriminatorStrategy
(String name, Discriminator discrim) {
if (NoneDiscriminatorStrategy.ALIAS.equals(name))
return NoneDiscriminatorStrategy.getInstance();
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
Class<?> strat = null;
if (ClassNameDiscriminatorStrategy.ALIAS.equals(name))
strat = ClassNameDiscriminatorStrategy.class;
else if (ValueMapDiscriminatorStrategy.ALIAS.equals(name))
strat = ValueMapDiscriminatorStrategy.class;
else if (SubclassJoinDiscriminatorStrategy.ALIAS.equals(name))
strat = SubclassJoinDiscriminatorStrategy.class;
try {
if (strat == null)
strat = JavaTypes.classForName(name,
discrim.getClassMapping(),
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(
DiscriminatorStrategy.class)), false);
DiscriminatorStrategy strategy = (DiscriminatorStrategy)
AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(strat));
Configurations.configureInstance(strategy, getConfiguration(),
props);
return strategy;
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-discrim-strategy",
discrim.getClassMapping(), name), e);
}
}
/**
* Instantiate the given version's named strategy, or return null
* if no named strategy.
*/
protected VersionStrategy namedStrategy(Version version) {
String name = version.getMappingInfo().getStrategy();
if (name == null)
return null;
// if there is a named strategy present, discard it if it matches
// the base strategy, so that we won't create an independent instance
ClassMapping cls = version.getClassMapping();
while (cls.getJoinablePCSuperclassMapping() != null)
cls = cls.getJoinablePCSuperclassMapping();
Version base = cls.getVersion();
if (base != version && base.getStrategy() != null
&& name.equals(base.getStrategy().getAlias()))
return null;
return instantiateVersionStrategy(name, version);
}
/**
* Instantiate the given version strategy.
*/
protected VersionStrategy instantiateVersionStrategy(String name,
Version version) {
if (NoneVersionStrategy.ALIAS.equals(name))
return NoneVersionStrategy.getInstance();
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
Class<?> strat = null;
if (NumberVersionStrategy.ALIAS.equals(name))
strat = NumberVersionStrategy.class;
else if (MultiColumnVersionStrategy.ALIAS.equals(name))
strat = MultiColumnVersionStrategy.class;
else if (TimestampVersionStrategy.ALIAS.equals(name))
strat = TimestampVersionStrategy.class;
else if (NanoPrecisionTimestampVersionStrategy.ALIAS.equals(name))
strat = NanoPrecisionTimestampVersionStrategy.class;
else if (StateComparisonVersionStrategy.ALIAS.equals(name))
strat = StateComparisonVersionStrategy.class;
try {
if (strat == null)
strat = JavaTypes.classForName(name,
version.getClassMapping(),
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(
VersionStrategy.class)), false);
} catch (Exception e) {
throw new MetaDataException(_loc.get("bad-version-strategy",
version.getClassMapping(), name), e);
}
return instantiateVersionStrategy(strat, version, props);
}
/**
* Instantiate the given version strategy.
*/
protected VersionStrategy instantiateVersionStrategy(Class<?> strat,
Version version, String props) {
try {
VersionStrategy strategy = (VersionStrategy)
AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(strat));
Configurations.configureInstance(strategy, getConfiguration(),
props);
return strategy;
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-version-strategy",
version.getClassMapping(), strat + ""), e);
}
}
/**
* Determine the default strategy to use for the given class. Does
* not take into account the current strategy, if any.
*/
protected ClassStrategy defaultStrategy(ClassMapping cls) {
return defaultStrategy(cls, getStrategyInstaller().isAdapting());
}
/**
* Determine the default strategy to use for the given class. Does
* not take into account the current strategy, if any.
*/
protected ClassStrategy defaultStrategy(ClassMapping cls,
boolean adapting) {
ValueMapping embed = cls.getEmbeddingMapping();
if (embed != null) {
// superclass of embedded class isn't mapped
if (embed.getType() != cls.getDescribedType()
|| embed.getFieldMapping().getStrategy()
== NoneFieldStrategy.getInstance())
return NoneClassStrategy.getInstance();
if (embed.getTypeCode() == JavaTypes.OID)
return new ObjectIdClassStrategy();
return new EmbeddedClassStrategy();
}
if (cls.isEmbeddedOnly())
return NoneClassStrategy.getInstance();
Object strat = _defaults.getStrategy(cls, adapting);
if (strat instanceof String)
return instantiateClassStrategy((String) strat, cls);
if (strat != null)
return (ClassStrategy) strat;
// see if there is a declared hierarchy strategy
ClassStrategy hstrat = null;
for (ClassMapping base = cls; base != null && hstrat == null;) {
hstrat = instantiateClassStrategy(base.getMappingInfo().
getHierarchyStrategy(), cls);
base = base.getMappedPCSuperclassMapping();
}
// the full strategy as applied to a hierarchy is a
// table-per-concrete-class strategy, so don't map abstract types
if (hstrat instanceof FullClassStrategy
&& !cls.isManagedInterface()
&& Modifier.isAbstract(cls.getDescribedType().getModifiers()))
return NoneClassStrategy.getInstance();
ClassMapping sup = cls.getMappedPCSuperclassMapping();
if (sup == null)
return new FullClassStrategy();
if (hstrat != null)
return hstrat;
return new FlatClassStrategy();
}
/**
* Determine the default strategy to use for the given field. Does
* not take into account the named or current strategy, if any. If a
* non-null strategy is returned, this method may as a side effect install
* value handlers on the field's value mappings.
*/
protected FieldStrategy defaultStrategy(FieldMapping field,
boolean installHandlers) {
return defaultStrategy(field, installHandlers,
getStrategyInstaller().isAdapting());
}
/**
* Determine the default strategy to use for the given field. Does
* not take into account the named or current strategy, if any. If a
* non-null strategy is returned, this method may as a side effect install
* value handlers on the field's value mappings.
*/
protected FieldStrategy defaultStrategy(FieldMapping field,
boolean installHandlers, boolean adapting) {
// not persistent?
if (field.getManagement() != FieldMetaData.MANAGE_PERSISTENT
|| field.isVersion())
return NoneFieldStrategy.getInstance();
if (field.getDefiningMapping().getStrategy() ==
NoneClassStrategy.getInstance())
return NoneFieldStrategy.getInstance();
// check for named handler first
ValueHandler handler = namedHandler(field);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
return new HandlerFieldStrategy();
}
// check for an explicitly mapped strategy
Object explicitStrat = mappedStrategy(field, field.getType(), adapting);
if (explicitStrat != null) {
if (explicitStrat instanceof FieldStrategy)
return (FieldStrategy) explicitStrat;
if (explicitStrat != null) {
if (installHandlers)
field.setHandler((ValueHandler) explicitStrat);
return new HandlerFieldStrategy();
}
}
if (field.isSerialized()) {
if (_dict.maxEmbeddedBlobSize != -1) {
handler = defaultHandler(field, adapting);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
}
return new MaxEmbeddedBlobFieldStrategy();
}
}
// check for known field strategies
if (!field.isSerialized() && (field.getType() == byte[].class
|| field.getType() == Byte[].class)) {
if (_dict.maxEmbeddedBlobSize != -1) {
handler = defaultHandler(field, adapting);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
}
return new MaxEmbeddedByteArrayFieldStrategy();
}
} else if (!field.isSerialized()
&& (field.getType() == char[].class
|| field.getType() == Character[].class)) {
if (_dict.maxEmbeddedClobSize != -1 && isClob(field, false)) {
handler = defaultHandler(field, adapting);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
}
return new MaxEmbeddedCharArrayFieldStrategy();
}
} else if (!field.isSerialized()) {
FieldStrategy strat = defaultTypeStrategy(field, installHandlers,
adapting);
if (strat != null) {
handler = defaultHandler(field, adapting);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
}
return strat;
}
}
// check for default handler
handler = defaultHandler(field, adapting);
if (handler != null) {
if (installHandlers)
field.setHandler(handler);
return new HandlerFieldStrategy();
}
// default to blob
if (installHandlers) {
if (getLog().isWarnEnabled())
getLog().warn(_loc.get("no-field-strategy", field));
field.setSerialized(true);
}
if (_dict.maxEmbeddedBlobSize == -1) {
if (installHandlers)
field.setHandler(BlobValueHandler.getInstance());
return new HandlerFieldStrategy();
}
return new MaxEmbeddedBlobFieldStrategy();
}
/**
* Return the built-in strategy for the field's type, or null if none.
*/
protected FieldStrategy defaultTypeStrategy(FieldMapping field,
boolean installHandlers, boolean adapting) {
switch (field.getTypeCode()) {
case JavaTypes.BOOLEAN:
case JavaTypes.BYTE:
case JavaTypes.CHAR:
case JavaTypes.DOUBLE:
case JavaTypes.FLOAT:
case JavaTypes.INT:
case JavaTypes.LONG:
case JavaTypes.SHORT:
return new PrimitiveFieldStrategy();
case JavaTypes.STRING:
if (!isClob(field, false))
return new StringFieldStrategy();
if (_dict.maxEmbeddedClobSize != -1)
return new MaxEmbeddedClobFieldStrategy();
break;
case JavaTypes.PC:
if (field.isEmbeddedPC())
return new EmbedFieldStrategy();
if (field.getTypeMapping().isMapped()
|| !useUntypedPCHandler(field))
return new RelationFieldStrategy();
break;
case JavaTypes.ARRAY:
case JavaTypes.COLLECTION:
ValueMapping elem = field.getElementMapping();
ValueHandler ehandler = namedHandler(elem);
if (ehandler == null)
ehandler = defaultHandler(elem);
if (ehandler != null)
return handlerCollectionStrategy(field, ehandler,
installHandlers);
if (elem.getTypeCode() == JavaTypes.PC
&& !elem.isSerialized() && !elem.isEmbeddedPC()) {
if (useInverseKeyMapping(field))
return new RelationCollectionInverseKeyFieldStrategy();
return new RelationCollectionTableFieldStrategy();
}
break;
case JavaTypes.MAP:
ValueMapping key = field.getKeyMapping();
ValueHandler khandler = namedHandler(key);
if (khandler == null)
khandler = defaultHandler(key);
ValueMapping val = field.getElementMapping();
ValueHandler vhandler = namedHandler(val);
if (vhandler == null)
vhandler = defaultHandler(val);
boolean krel = khandler == null
&& key.getTypeCode() == JavaTypes.PC
&& !key.isSerialized() && !key.isEmbeddedPC();
boolean vrel = vhandler == null
&& val.getTypeCode() == JavaTypes.PC
&& !val.isSerialized() && !val.isEmbeddedPC();
if (vrel && key.getValueMappedBy() != null) {
if (useInverseKeyMapping(field))
return new RelationMapInverseKeyFieldStrategy();
return new RelationMapTableFieldStrategy();
}
//TODO: in JPA 2.0 if MapKeyClass type is not specified
// an exception is thrown. In OpenJpa 1.x, the map will
// be serialized to a blob (the null value returned by
// this method will lead to a strategy to serialize
// the map).
if (!krel && khandler == null)
break;
if (!vrel && vhandler == null)
break;
return handlerMapStrategy(field, khandler, vhandler, krel,
vrel, installHandlers);
case JavaTypes.INPUT_STREAM:
case JavaTypes.INPUT_READER:
return new LobFieldStrategy();
}
return null;
}
/**
* Return the collection strategy for the given element handler, or null
* if none.
*/
protected FieldStrategy handlerCollectionStrategy(FieldMapping field,
ValueHandler ehandler, boolean installHandlers) {
// TODO: JPA 2.0 should ignore this flag and not to serialize
if (getConfiguration().getCompatibilityInstance()
.getStoreMapCollectionInEntityAsBlob())
return null;
if (installHandlers)
field.getElementMapping().setHandler(ehandler);
return new HandlerCollectionTableFieldStrategy();
}
/**
* Return the map strategy for the given key and value handlers / relations,
* or null if none.
*/
protected FieldStrategy handlerMapStrategy(FieldMapping field,
ValueHandler khandler, ValueHandler vhandler, boolean krel,
boolean vrel, boolean installHandlers) {
// TODO: JPA 2.0 should ignore this flag and not to serialize
if (getConfiguration().getCompatibilityInstance()
.getStoreMapCollectionInEntityAsBlob())
return null;
if (installHandlers) {
field.getKeyMapping().setHandler(khandler);
field.getElementMapping().setHandler(vhandler);
}
if (!krel && !vrel)
return new HandlerHandlerMapTableFieldStrategy();
if (!krel && vrel)
return new HandlerRelationMapTableFieldStrategy();
if (krel && !vrel)
return new RelationHandlerMapTableFieldStrategy();
return new RelationRelationMapTableFieldStrategy();
}
/**
* Use hints in mapping data to figure out whether the given relation
* field should use an inverse foreign key or an association table mapping.
*/
private boolean useInverseKeyMapping(FieldMapping field) {
FieldMapping mapped = field.getMappedByMapping();
if (mapped != null) {
//bi-/M-1/JoinTable ==> join table strategy
if (isBiMTo1JT(field))
return false;
if (mapped.getTypeCode() == JavaTypes.PC || mapped.getTypeCode() == JavaTypes.PC_UNTYPED)
return true;
if (mapped.getElement().getTypeCode() == JavaTypes.PC)
return false;
throw new MetaDataException(_loc.get("bad-mapped-by", field,
mapped));
}
// without a mapped-by, we have to look for clues as to the mapping.
// we assume that anything with element foreign key columns but no join
// columns or table uses an inverse foreign key, and anything else uses
// an association table
FieldMappingInfo info = field.getMappingInfo();
ValueMapping elem = field.getElementMapping();
boolean useInverseKeyMapping = DBIdentifier.isNull(info.getTableIdentifier()) && info.getColumns().isEmpty()
&& !elem.getValueInfo().getColumns().isEmpty();
// JPA 2.0: non-default mapping: uni-/1-M/JoinColumn ==> foreign key strategy
if (isUni1ToMFK(field)) {
return true;
}
return useInverseKeyMapping;
}
public boolean isNonDefaultMappingAllowed() {
OpenJPAConfiguration conf = getConfiguration();
return getMetaDataFactory().getDefaults().isNonDefaultMappingAllowed(conf);
}
public boolean isUniMTo1JT(FieldMapping field) {
if (isNonDefaultMappingAllowed() &&
field.getAssociationType() == FieldMetaData.MANY_TO_ONE &&
hasJoinTable(field) &&
!isBidirectional(field)) {
List<Column> cols = field.getElementMapping().getValueInfo().getColumns();
if (cols != null && cols.size() > 0) {
field.getValueMapping().getValueInfo().setColumns(cols);
}
return true;
}
return false;
}
public boolean isUni1To1JT(FieldMapping field) {
if (isNonDefaultMappingAllowed() &&
field.getAssociationType() == FieldMetaData.ONE_TO_ONE &&
hasJoinTable(field) &&
!isBidirectional(field)) {
List<Column> cols = field.getElementMapping().getValueInfo().getColumns();
if (cols != null && cols.size() > 0) {
field.getValueMapping().getValueInfo().setColumns(cols);
}
return true;
}
return false;
}
public boolean isBi1To1JT(FieldMapping field) {
if (isNonDefaultMappingAllowed() &&
field.getAssociationType() == FieldMetaData.ONE_TO_ONE &&
hasJoinTable(field) &&
isBidirectional(field)) {
List<Column> cols = field.getElementMapping().getValueInfo().getColumns();
if (cols != null && cols.size() > 0) {
field.getValueMapping().getValueInfo().setColumns(cols);
}
return true;
}
return false;
}
public boolean isUni1ToMFK(FieldMapping field) {
if (isNonDefaultMappingAllowed() &&
field.getAssociationType() == FieldMetaData.ONE_TO_MANY &&
hasJoinColumn(field) &&
!isBidirectional(field)) {
field.getElementMapping().getValueInfo().setColumns(field.getValueInfo().getColumns());
return true;
}
return false;
}
public boolean isBiMTo1JT(FieldMapping field) {
FieldMapping mapped = field.getMappedByMapping();
if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY ) {
if (mapped != null && hasJoinTable(mapped))
return true;
} else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
if (getBi_1ToM_JoinTableField(field) != null)
return true;
}
}
return false;
}
// return the inverse field of bidirectional many to one
// relation using join table strategy
public FieldMapping getBi_1ToM_JoinTableField(FieldMapping field) {
if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) {
FieldMapping mappedBy = field.getMappedByMapping();
if (mappedBy != null && hasJoinTable(mappedBy))
return field;
} else if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
if (!hasJoinTable(field))
return null;
ClassMapping inverse = field.getValueMapping().getTypeMapping();
FieldMapping[] fmds = inverse.getFieldMappings();
for (FieldMapping fmd : fmds) {
if (field == fmd.getMappedByMapping())
return fmd;
}
}
}
return null;
}
// return the owning field of bidirectional one to many
// relation using join table strategy
public FieldMapping getBi_MTo1_JoinTableField(FieldMapping field) {
if (isNonDefaultMappingAllowed()) {
if (field.getAssociationType() == FieldMetaData.MANY_TO_ONE) {
if (!hasJoinTable(field))
return null;
if (isBidirectional(field))
return field;
} else if (field.getAssociationType() == FieldMetaData.ONE_TO_MANY) {
FieldMapping mappedBy = field.getMappedByMapping();
if (mappedBy != null && hasJoinTable(mappedBy))
return mappedBy;
}
}
return null;
}
public boolean hasJoinColumn(FieldMapping field) {
boolean hasJoinColumn = (field.getValueInfo().getColumns().size() > 0 ? true : false);
return hasJoinColumn;
}
public boolean hasJoinTable(FieldMapping field) {
boolean hasJoinTable = !DBIdentifier.isNull(field.getMappingInfo().getTableIdentifier()) ? true : false;
return hasJoinTable;
}
public boolean isBidirectional(FieldMapping field) {
if (field.getMappedByMapping() != null) return true;
int assoType = field.getAssociationType();
if (assoType == FieldMetaData.ONE_TO_ONE ||
assoType == FieldMetaData.MANY_TO_ONE) {
ClassMapping inverse = field.getValueMapping().getTypeMapping();
FieldMapping[] fmds = inverse.getFieldMappings();
for (FieldMapping fmd : fmds) {
if (field == fmd.getMappedByMapping())
return true;
}
}
return false;
}
/**
* Check the given value against mapped strategies.
*/
private Object mappedStrategy(ValueMapping val, Class<?> type,
boolean adapting) {
if (type == null || type == Object.class)
return null;
Object strat = _defaults.getStrategy(val, type, adapting);
// recurse on superclass so that, for example, a registered handler
// for java.lang.Enum will work on all enums
if (strat == null)
return mappedStrategy(val, type.getSuperclass(), adapting);
if (!(strat instanceof String))
return strat;
String name = (String) strat;
if (NoneFieldStrategy.ALIAS.equals(name))
return NoneFieldStrategy.getInstance();
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
try {
Class<?> c = JavaTypes.classForName(name, val,
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(FieldStrategy.class)),false);
Object o = AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(c));
Configurations.configureInstance(o, getConfiguration(), props);
return o;
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-mapped-strategy",
val, name), e);
}
}
/**
* Instantiate the given value's named handler, or return null if no
* named handler.
*/
protected ValueHandler namedHandler(ValueMapping val) {
String name = val.getValueInfo().getStrategy();
if (name == null)
return null;
String props = Configurations.getProperties(name);
name = Configurations.getClassName(name);
try {
Class<?> c = JavaTypes.classForName(name, val,
AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(ValueHandler.class)),false);
if (ValueHandler.class.isAssignableFrom(c)) {
ValueHandler vh = (ValueHandler) AccessController.doPrivileged(
J2DoPrivHelper.newInstanceAction(c));
Configurations.configureInstance(vh, getConfiguration(),
props);
return vh;
}
return null; // named field strategy
} catch (Exception e) {
if (e instanceof PrivilegedActionException)
e = ((PrivilegedActionException) e).getException();
throw new MetaDataException(_loc.get("bad-value-handler",
val, name), e);
}
}
/**
* Determine the default handler to use for the given value. Does
* not take into account the named handler, if any.
*/
protected ValueHandler defaultHandler(ValueMapping val) {
return defaultHandler(val, getStrategyInstaller().isAdapting());
}
/**
* Determine the default handler to use for the given value. Does
* not take into account the named handler, if any.
*/
protected ValueHandler defaultHandler(ValueMapping val, boolean adapting) {
if (val.isSerialized()) {
if (_dict.maxEmbeddedBlobSize != -1)
warnMaxEmbedded(val, _dict.maxEmbeddedBlobSize);
return BlobValueHandler.getInstance();
}
Object handler = mappedStrategy(val, val.getType(), adapting);
if (handler instanceof ValueHandler)
return (ValueHandler) handler;
if (val.getType() == byte[].class
|| val.getType() == Byte[].class) {
if (_dict.maxEmbeddedBlobSize != -1)
warnMaxEmbedded(val, _dict.maxEmbeddedBlobSize);
return ByteArrayValueHandler.getInstance();
}
if (val.getType() == char[].class
|| val.getType() == Character[].class) {
if (isClob(val, true))
return CharArrayStreamValueHandler.getInstance();
return CharArrayValueHandler.getInstance();
}
switch (val.getTypeCode()) {
case JavaTypes.BOOLEAN:
case JavaTypes.BYTE:
case JavaTypes.CHAR:
case JavaTypes.DOUBLE:
case JavaTypes.FLOAT:
case JavaTypes.INT:
case JavaTypes.LONG:
case JavaTypes.SHORT:
case JavaTypes.BOOLEAN_OBJ:
case JavaTypes.BYTE_OBJ:
case JavaTypes.CHAR_OBJ:
case JavaTypes.DOUBLE_OBJ:
case JavaTypes.FLOAT_OBJ:
case JavaTypes.INT_OBJ:
case JavaTypes.LONG_OBJ:
case JavaTypes.SHORT_OBJ:
case JavaTypes.BIGINTEGER:
case JavaTypes.BIGDECIMAL:
case JavaTypes.NUMBER:
case JavaTypes.DATE:
case JavaTypes.CALENDAR:
case JavaTypes.LOCALE:
case JavaTypes.LOCAL_DATE:
case JavaTypes.LOCAL_TIME:
case JavaTypes.LOCAL_DATETIME:
case JavaTypes.OFFSET_TIME:
case JavaTypes.OFFSET_DATETIME:
return ImmutableValueHandler.getInstance();
case JavaTypes.STRING:
if (isClob(val, true))
return ClobValueHandler.getInstance();
return ImmutableValueHandler.getInstance();
case JavaTypes.PC:
if (!val.getTypeMapping().isMapped()
&& useUntypedPCHandler(val))
return UntypedPCValueHandler.getInstance();
break;
case JavaTypes.PC_UNTYPED:
return UntypedPCValueHandler.getInstance();
case JavaTypes.OID:
return new ObjectIdValueHandler();
}
if (!getConfiguration().getCompatibilityInstance()
.getStoreMapCollectionInEntityAsBlob()
&& val.isEmbeddedPC())
return new ElementEmbedValueHandler();
return null;
}
/**
* Return true if we should use the generic untyped PC handler for the
* given unmapped relation.
*/
private boolean useUntypedPCHandler(ValueMapping val) {
ClassMapping rel = val.getTypeMapping();
return rel.getIdentityType() == ClassMetaData.ID_UNKNOWN
|| (rel.getIdentityType() == ClassMetaData.ID_APPLICATION
&& (rel.getPrimaryKeyFields().length == 0
|| (!rel.isOpenJPAIdentity() && Modifier.isAbstract
(rel.getObjectIdType().getModifiers()))));
}
/**
* Checks for hints as to whether the given column is a CLOB.
*/
private boolean isClob(ValueMapping val, boolean warn) {
List<Column> cols = val.getValueInfo().getColumns();
if (cols.size() != 1)
return false;
Column col = (Column) cols.get(0);
if (col.getSize() != -1 && col.getType() != Types.CLOB)
return false;
if (_dict.getPreferredType(Types.CLOB) != Types.CLOB)
return false;
if (warn && _dict.maxEmbeddedClobSize != -1)
warnMaxEmbedded(val, _dict.maxEmbeddedClobSize);
return true;
}
/**
* Warn that the given value is being mapped to a handler that will not
* be able to store large lobs.
*/
private void warnMaxEmbedded(ValueMapping val, int size) {
if (getLog().isWarnEnabled())
getLog().warn(_loc.get("max-embed-lob", val,
String.valueOf(size)));
}
/**
* Determine the default strategy to use for the given discriminator.
* Does not take into account the current strategy, if any.
*/
protected DiscriminatorStrategy defaultStrategy(Discriminator discrim) {
return defaultStrategy(discrim, getStrategyInstaller().isAdapting());
}
/**
* Determine the default strategy to use for the given discriminator.
* Does not take into account the current strategy, if any.
*/
protected DiscriminatorStrategy defaultStrategy(Discriminator discrim,
boolean adapting) {
ClassMapping cls = discrim.getClassMapping();
if (cls.getEmbeddingMetaData() != null)
return NoneDiscriminatorStrategy.getInstance();
if (cls.getJoinablePCSuperclassMapping() == null
&& (cls.getStrategy() == NoneClassStrategy.getInstance()
|| Modifier.isFinal(discrim.getClassMapping().getDescribedType().
getModifiers())))
return NoneDiscriminatorStrategy.getInstance();
Object strat = _defaults.getStrategy(discrim, adapting);
if (strat instanceof String)
return instantiateDiscriminatorStrategy((String) strat, discrim);
if (strat != null)
return (DiscriminatorStrategy) strat;
if (cls.getJoinablePCSuperclassMapping() != null)
return new SuperclassDiscriminatorStrategy();
if (discrim.getMappingInfo().getValue() != null)
return new ValueMapDiscriminatorStrategy();
if (cls.getMappedPCSuperclassMapping() != null)
return NoneDiscriminatorStrategy.getInstance();
if (adapting || _defaults.defaultMissingInfo())
return new ClassNameDiscriminatorStrategy();
DBDictionary dict = ((JDBCConfiguration) getConfiguration()).
getDBDictionaryInstance();
if (dict.joinSyntax == JoinSyntaxes.SYNTAX_TRADITIONAL)
return NoneDiscriminatorStrategy.getInstance();
return new SubclassJoinDiscriminatorStrategy();
}
/**
* Determine the default strategy to use for the given version.
* Does not take into account the current strategy, if any.
*/
protected VersionStrategy defaultStrategy(Version version) {
return defaultStrategy(version, getStrategyInstaller().isAdapting());
}
/**
* Determine the default strategy to use for the given version.
* Does not take into account the current strategy, if any.
*/
protected VersionStrategy defaultStrategy(Version version,
boolean adapting) {
ClassMapping cls = version.getClassMapping();
if (cls.getEmbeddingMetaData() != null)
return NoneVersionStrategy.getInstance();
if (cls.getJoinablePCSuperclassMapping() == null
&& cls.getStrategy() == NoneClassStrategy.getInstance())
return NoneVersionStrategy.getInstance();
Object strat = _defaults.getStrategy(version, adapting);
if (strat instanceof String)
return instantiateVersionStrategy((String) strat, version);
if (strat != null)
return (VersionStrategy) strat;
if (cls.getJoinablePCSuperclassMapping() != null)
return new SuperclassVersionStrategy();
FieldMapping vfield = version.getClassMapping().
getVersionFieldMapping();
if (vfield != null)
return defaultStrategy(version, vfield);
if (adapting || _defaults.defaultMissingInfo())
return new NumberVersionStrategy();
return NoneVersionStrategy.getInstance();
}
/**
* Return the default version strategy, given a version field.
*/
protected VersionStrategy defaultStrategy(Version vers,
FieldMapping vfield) {
switch (vfield.getTypeCode()) {
case JavaTypes.DATE:
case JavaTypes.CALENDAR:
return new NanoPrecisionTimestampVersionStrategy();
case JavaTypes.BYTE:
case JavaTypes.INT:
case JavaTypes.LONG:
case JavaTypes.SHORT:
case JavaTypes.BYTE_OBJ:
case JavaTypes.INT_OBJ:
case JavaTypes.LONG_OBJ:
case JavaTypes.SHORT_OBJ:
case JavaTypes.NUMBER:
return new NumberVersionStrategy();
default:
throw new UserException(_loc.get("version-type-unsupported", vfield, vfield.getDeclaredType()));
}
}
@Override
public void endConfiguration() {
super.endConfiguration();
JDBCConfiguration conf = (JDBCConfiguration) getConfiguration();
_dict = conf.getDBDictionaryInstance();
if (_defaults == null)
_defaults = conf.getMappingDefaultsInstance();
if (_schema != null && _schema instanceof Configurable) {
((Configurable) _schema).setConfiguration(conf);
((Configurable) _schema).startConfiguration();
((Configurable) _schema).endConfiguration();
}
}
/**
* Finds the base class mapping for the specified mapping. Loads all
* persistent types if necessary, since all persistent subclasses of this
* mapping may not have been resolved before this method is called.
*/
protected ClassMapping findBaseClassMapping(ClassMapping mapping) {
ClassMapping baseMapping = null;
ClassMapping sup = mapping.getPCSuperclassMapping();
if (sup == null) {
// no superclass metadata was provided. check to see if this class
// has any persistent subclasses.
if (mapping.getPCSubclasses().length > 0)
baseMapping = mapping;
else {
// persistent subclasses may not have been resolved yet.
// run through the persistent types to see if any of them
// or their superclass is a subclass of this class.
Collection<Class<?>> classes = loadPersistentTypes(false,
mapping.getEnvClassLoader());
Class<?> cls;
for (Class<?> aClass : classes) {
cls = aClass;
Class<?> supcl = cls.getSuperclass();
while (supcl != null &&
!supcl.equals(Object.class)) {
if (!supcl.isInterface() &&
supcl.equals(mapping.getDescribedType())) {
baseMapping = mapping;
break;
}
supcl = supcl.getSuperclass();
}
if (baseMapping != null) break;
}
}
} else if (!sup.getDescribedType().isInterface()) {
// if the superclass is not a managed interface, find the root
// superclass and get its mapping info
ClassMapping supcm = sup;
while (supcm != null &&
!supcm.getDescribedType().isInterface() &&
!supcm.isEmbeddedOnly()) {
ClassMapping supcm2 = supcm.getPCSuperclassMapping();
if (supcm2 == null)
baseMapping = supcm;
supcm = supcm2;
}
}
return baseMapping;
}
/**
* If an inheritance strategy has not been set on this mapping, set it
* to the default (flat). This method should be called before strategies
* are created for the specified mapping.
*/
protected void setDefaultInheritanceStrategy(ClassMapping mapping) {
ClassMappingInfo info = mapping.getMappingInfo();
if (info != null && info.getHierarchyStrategy() == null)
info.setHierarchyStrategy(FlatClassStrategy.ALIAS);
}
/**
* Determines whether an inhertance strategy has been set on the
* specified mapping.
*/
protected boolean hasInheritanceStrategy(ClassMapping mapping) {
ClassMappingInfo info = mapping.getMappingInfo();
if (info != null && info.getHierarchyStrategy() != null)
return true;
return false;
}
}