| /* |
| * 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; |
| } |
| } |