0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one
0003: * or more contributor license agreements. See the NOTICE file
0004: * distributed with this work for additional information
0005: * regarding copyright ownership. The ASF licenses this file
0006: * to you under the Apache License, Version 2.0 (the
0007: * "License"); you may not use this file except in compliance
0008: * with the License. You may obtain a copy of the License at
0009: *
0010: * http://www.apache.org/licenses/LICENSE-2.0
0011: *
0012: * Unless required by applicable law or agreed to in writing,
0013: * software distributed under the License is distributed on an
0014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
0015: * KIND, either express or implied. See the License for the
0016: * specific language governing permissions and limitations
0017: * under the License.
0018: */
0019: package org.apache.openjpa.jdbc.meta;
0020:
0021: import java.sql.SQLException;
0022: import java.util.ArrayList;
0023: import java.util.Arrays;
0024: import java.util.Collection;
0025: import java.util.Collections;
0026: import java.util.HashMap;
0027: import java.util.Iterator;
0028: import java.util.LinkedHashSet;
0029: import java.util.List;
0030: import java.util.Map;
0031: import java.util.Set;
0032:
0033: import org.apache.commons.lang.StringUtils;
0034: import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
0035: import org.apache.openjpa.jdbc.kernel.JDBCStore;
0036: import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy;
0037: import org.apache.openjpa.jdbc.schema.Column;
0038: import org.apache.openjpa.jdbc.schema.ColumnIO;
0039: import org.apache.openjpa.jdbc.schema.ForeignKey;
0040: import org.apache.openjpa.jdbc.schema.Schemas;
0041: import org.apache.openjpa.jdbc.schema.Table;
0042: import org.apache.openjpa.jdbc.sql.Joins;
0043: import org.apache.openjpa.jdbc.sql.Result;
0044: import org.apache.openjpa.jdbc.sql.RowManager;
0045: import org.apache.openjpa.jdbc.sql.Select;
0046: import org.apache.openjpa.kernel.FetchConfiguration;
0047: import org.apache.openjpa.kernel.OpenJPAStateManager;
0048: import org.apache.openjpa.kernel.PCState;
0049: import org.apache.openjpa.lib.log.Log;
0050: import org.apache.openjpa.lib.rop.ResultObjectProvider;
0051: import org.apache.openjpa.lib.util.Localizer;
0052: import org.apache.openjpa.meta.ClassMetaData;
0053: import org.apache.openjpa.meta.ValueMetaData;
0054: import org.apache.openjpa.util.ApplicationIds;
0055: import org.apache.openjpa.util.InternalException;
0056: import org.apache.openjpa.util.MetaDataException;
0057: import org.apache.openjpa.util.OpenJPAId;
0058: import org.apache.openjpa.util.ImplHelper;
0059:
0060: /**
0061: * Specialization of metadata for relational databases.
0062: *
0063: * @author Abe White
0064: */
0065: public class ClassMapping extends ClassMetaData implements
0066: ClassStrategy {
0067:
0068: public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0];
0069:
0070: private static final Localizer _loc = Localizer
0071: .forPackage(ClassMapping.class);
0072:
0073: private final ClassMappingInfo _info;
0074: private final Discriminator _discrim;
0075: private final Version _version;
0076: private ClassStrategy _strategy = null;
0077:
0078: private Table _table = null;
0079: private ColumnIO _io = null;
0080: private Column[] _cols = Schemas.EMPTY_COLUMNS;
0081: private ForeignKey _fk = null;
0082: private int _subclassMode = Integer.MAX_VALUE;
0083:
0084: private ClassMapping[] _joinSubMaps = null;
0085: private ClassMapping[] _assignMaps = null;
0086:
0087: // maps columns to joinables
0088: private final Map _joinables = Collections
0089: .synchronizedMap(new HashMap());
0090:
0091: /**
0092: * Constructor. Supply described type and owning repository.
0093: */
0094: protected ClassMapping(Class type, MappingRepository repos) {
0095: super (type, repos);
0096: _discrim = repos.newDiscriminator(this );
0097: _version = repos.newVersion(this );
0098: _info = repos.newMappingInfo(this );
0099: }
0100:
0101: /**
0102: * Embedded constructor. Supply embedding value and owning repository.
0103: */
0104: protected ClassMapping(ValueMetaData vmd) {
0105: super (vmd);
0106: _discrim = getMappingRepository().newDiscriminator(this );
0107: _version = getMappingRepository().newVersion(this );
0108: _info = getMappingRepository().newMappingInfo(this );
0109: }
0110:
0111: /**
0112: * The class discriminator.
0113: */
0114: public Discriminator getDiscriminator() {
0115: return _discrim;
0116: }
0117:
0118: /**
0119: * The version indicator.
0120: */
0121: public Version getVersion() {
0122: return _version;
0123: }
0124:
0125: ///////////
0126: // Runtime
0127: ///////////
0128:
0129: /**
0130: * Return the oid value stored in the result. This implementation will
0131: * recurse until it finds an ancestor class who uses oid values for its
0132: * primary key.
0133: *
0134: * @param fk if non-null, use the local columns of the given foreign
0135: * key in place of this class' primary key columns
0136: * @see #isPrimaryKeyObjectId
0137: */
0138: public Object getObjectId(JDBCStore store, Result res,
0139: ForeignKey fk, boolean subs, Joins joins)
0140: throws SQLException {
0141: ValueMapping embed = getEmbeddingMapping();
0142: if (embed != null)
0143: return embed.getFieldMapping().getDefiningMapping()
0144: .getObjectId(store, res, fk, subs, joins);
0145:
0146: return getObjectId(this , store, res, fk, subs, joins);
0147: }
0148:
0149: /**
0150: * Recursive helper for public <code>getObjectId</code> method.
0151: */
0152: private Object getObjectId(ClassMapping cls, JDBCStore store,
0153: Result res, ForeignKey fk, boolean subs, Joins joins)
0154: throws SQLException {
0155: if (!isPrimaryKeyObjectId(true))
0156: return getPCSuperclassMapping().getObjectId(cls, store,
0157: res, fk, subs, joins);
0158: if (getIdentityType() == ID_UNKNOWN)
0159: throw new InternalException();
0160:
0161: Column[] pks = getPrimaryKeyColumns();
0162: if (getIdentityType() == ID_DATASTORE) {
0163: Column col = (fk == null) ? pks[0] : fk.getColumn(pks[0]);
0164: long id = res.getLong(col, joins);
0165: return (id == 0 && res.wasNull()) ? null : store
0166: .newDataStoreId(id, cls, subs);
0167: }
0168:
0169: // application identity
0170: Object[] vals = new Object[getPrimaryKeyFields().length];
0171: FieldMapping fm;
0172: Joinable join;
0173: int pkIdx;
0174: for (int i = 0; i < pks.length; i++) {
0175: // we know that all pk column join mappings use primary key fields,
0176: // cause this mapping uses the oid as its primary key (we recursed
0177: // at the beginning of the method to ensure this)
0178: join = assertJoinable(pks[i]);
0179: fm = getFieldMapping(join.getFieldIndex());
0180: pkIdx = fm.getPrimaryKeyIndex();
0181:
0182: // could have already set value with previous multi-column joinable
0183: if (vals[pkIdx] == null) {
0184: res.startDataRequest(fm);
0185: vals[pkIdx] = join.getPrimaryKeyValue(res, join
0186: .getColumns(), fk, store, joins);
0187: res.endDataRequest();
0188: if (vals[pkIdx] == null)
0189: return null;
0190: }
0191: }
0192: Object oid = ApplicationIds.fromPKValues(vals, cls);
0193:
0194: /**
0195: * For polymorphic relations,
0196: * the type field in the oid is initially set to base type.
0197: * If the discriminator value is preset in the current result,
0198: * then the type field needs reset based on the discriminator value.
0199: * If the discriminator value is not present or invalid,
0200: * ignore any exceptions being thrown.
0201: */
0202: if (oid instanceof OpenJPAId) {
0203: Class type = cls.getDescribedType();
0204: if (!subs)
0205: // non-polymorphic relations
0206: ((OpenJPAId) oid).setManagedInstanceType(type);
0207: else if (cls.getDiscriminator() != null
0208: && !StringUtils.equals("none", cls
0209: .getDiscriminator().getStrategy()
0210: .getAlias())) {
0211: // polymorphic relations
0212: res.startDataRequest(cls.getDiscriminator());
0213: try {
0214: type = cls.getDiscriminator().getClass(store, cls,
0215: res);
0216: ((OpenJPAId) oid)
0217: .setManagedInstanceType(type, true);
0218: } catch (Exception e) {
0219: // intentionally ignored
0220: }
0221: res.endDataRequest();
0222: }
0223: }
0224: return oid;
0225: }
0226:
0227: /**
0228: * Return the given column value(s) for the given object. The given
0229: * columns will be primary key columns of this mapping, but may be in
0230: * any order. If there is only one column, return its value. If there
0231: * are multiple columns, return an object array of their values, in the
0232: * same order the columns are given.
0233: */
0234: public Object toDataStoreValue(Object obj, Column[] cols,
0235: JDBCStore store) {
0236: Object ret = (cols.length == 1) ? null
0237: : new Object[cols.length];
0238:
0239: // in the past we've been lenient about being able to translate objects
0240: // from other persistence contexts, so try to get sm directly from
0241: // instance before asking our context
0242: OpenJPAStateManager sm;
0243: if (ImplHelper.isManageable(obj))
0244: sm = (OpenJPAStateManager) (ImplHelper
0245: .toPersistenceCapable(obj, getRepository()
0246: .getConfiguration())).pcGetStateManager();
0247: else
0248: sm = store.getContext().getStateManager(obj);
0249: if (sm == null)
0250: return ret;
0251:
0252: Object val;
0253: for (int i = 0; i < cols.length; i++) {
0254: val = assertJoinable(cols[i]).getJoinValue(sm, cols[i],
0255: store);
0256: if (cols.length == 1)
0257: ret = val;
0258: else
0259: ((Object[]) ret)[i] = val;
0260: }
0261: return ret;
0262: }
0263:
0264: /**
0265: * Return the joinable for the given column, or throw an exception if
0266: * none is available.
0267: */
0268: public Joinable assertJoinable(Column col) {
0269: Joinable join = getJoinable(col);
0270: if (join == null)
0271: throw new MetaDataException(_loc.get("no-joinable", col
0272: .getFullName()));
0273: return join;
0274: }
0275:
0276: /**
0277: * Return the {@link Joinable} for the given column. Any column that
0278: * another mapping joins to must be controlled by a joinable.
0279: */
0280: public Joinable getJoinable(Column col) {
0281: Joinable join;
0282: if (getEmbeddingMetaData() != null) {
0283: join = getEmbeddingMapping().getFieldMapping()
0284: .getDefiningMapping().getJoinable(col);
0285: if (join != null)
0286: return join;
0287: }
0288: ClassMapping sup = getJoinablePCSuperclassMapping();
0289: if (sup != null) {
0290: join = sup.getJoinable(col);
0291: if (join != null)
0292: return join;
0293: }
0294: return (Joinable) _joinables.get(col);
0295: }
0296:
0297: /**
0298: * Add the given column-to-joinable mapping.
0299: */
0300: public void setJoinable(Column col, Joinable joinable) {
0301: // don't let non-pk override pk
0302: Joinable join = (Joinable) _joinables.get(col);
0303: if (join == null
0304: || (join.getFieldIndex() != -1 && getField(
0305: join.getFieldIndex()).getPrimaryKeyIndex() == -1))
0306: _joinables.put(col, joinable);
0307: }
0308:
0309: /**
0310: * Return whether the columns of the given foreign key to this mapping
0311: * can be used to construct an object id for this type. This is a
0312: * relatively expensive operation; its results should be cached.
0313: *
0314: * @return {@link Boolean#TRUE} if the foreign key contains all oid
0315: * columns, <code>null</code> if it contains only some columns,
0316: * or {@link Boolean#FALSE} if it contains non-oid columns
0317: */
0318: public Boolean isForeignKeyObjectId(ForeignKey fk) {
0319: // if this mapping's primary key can't construct an oid, then no way
0320: // foreign key can
0321: if (getIdentityType() == ID_UNKNOWN
0322: || !isPrimaryKeyObjectId(false))
0323: return Boolean.FALSE;
0324:
0325: // with datastore identity, it's all or nothing
0326: Column[] cols = fk.getPrimaryKeyColumns();
0327: if (getIdentityType() == ID_DATASTORE) {
0328: if (cols.length != 1
0329: || cols[0] != getPrimaryKeyColumns()[0])
0330: return Boolean.FALSE;
0331: return Boolean.TRUE;
0332: }
0333:
0334: // check the join mapping for each pk column to see if it links up to
0335: // a primary key field
0336: Joinable join;
0337: for (int i = 0; i < cols.length; i++) {
0338: join = assertJoinable(cols[i]);
0339: if (join.getFieldIndex() != -1
0340: && getField(join.getFieldIndex())
0341: .getPrimaryKeyIndex() == -1)
0342: return Boolean.FALSE;
0343: }
0344:
0345: // if all primary key links, see whether we join to all pks
0346: if (isPrimaryKeyObjectId(true)
0347: && cols.length == getPrimaryKeyColumns().length)
0348: return Boolean.TRUE;
0349: return null;
0350: }
0351:
0352: ///////
0353: // ORM
0354: ///////
0355:
0356: /**
0357: * Raw mapping data.
0358: */
0359: public ClassMappingInfo getMappingInfo() {
0360: return _info;
0361: }
0362:
0363: /**
0364: * The strategy used to map this mapping.
0365: */
0366: public ClassStrategy getStrategy() {
0367: return _strategy;
0368: }
0369:
0370: /**
0371: * The strategy used to map this mapping. The <code>adapt</code>
0372: * parameter determines whether to adapt when mapping the strategy;
0373: * use null if the strategy should not be mapped.
0374: */
0375: public void setStrategy(ClassStrategy strategy, Boolean adapt) {
0376: // set strategy first so we can access it during mapping
0377: ClassStrategy orig = _strategy;
0378: _strategy = strategy;
0379: if (strategy != null) {
0380: try {
0381: strategy.setClassMapping(this );
0382: if (adapt != null)
0383: strategy.map(adapt.booleanValue());
0384: } catch (RuntimeException re) {
0385: // reset strategy
0386: _strategy = orig;
0387: throw re;
0388: }
0389: }
0390: }
0391:
0392: /**
0393: * The mapping's primary table.
0394: */
0395: public Table getTable() {
0396: return _table;
0397: }
0398:
0399: /**
0400: * The mapping's primary table.
0401: */
0402: public void setTable(Table table) {
0403: _table = table;
0404: }
0405:
0406: /**
0407: * The columns this mapping uses to uniquely identify an object.
0408: * These will typically be the primary key columns or the columns this
0409: * class uses to link to its superclass table.
0410: */
0411: public Column[] getPrimaryKeyColumns() {
0412: if (_cols.length == 0 && getIdentityType() == ID_APPLICATION
0413: && isMapped()) {
0414: FieldMapping[] pks = getPrimaryKeyFieldMappings();
0415: Collection cols = new ArrayList(pks.length);
0416: Column[] fieldCols;
0417: for (int i = 0; i < pks.length; i++) {
0418: fieldCols = pks[i].getColumns();
0419: for (int j = 0; j < fieldCols.length; j++)
0420: cols.add(fieldCols[j]);
0421: }
0422: _cols = (Column[]) cols.toArray(new Column[cols.size()]);
0423: }
0424: return _cols;
0425: }
0426:
0427: /**
0428: * The columns this mapping uses to uniquely identify an object.
0429: * These will typically be the primary key columns or the columns this
0430: * class uses to link to its superclass table.
0431: */
0432: public void setPrimaryKeyColumns(Column[] cols) {
0433: if (cols == null)
0434: cols = Schemas.EMPTY_COLUMNS;
0435: _cols = cols;
0436: }
0437:
0438: /**
0439: * I/O information on the key columns / join key.
0440: */
0441: public ColumnIO getColumnIO() {
0442: return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
0443: }
0444:
0445: /**
0446: * I/O information on the key columns / join key.
0447: */
0448: public void setColumnIO(ColumnIO io) {
0449: _io = io;
0450: }
0451:
0452: /**
0453: * Foreign key linking the primary key columns to the superclass table,
0454: * or null if none.
0455: */
0456: public ForeignKey getJoinForeignKey() {
0457: return _fk;
0458: }
0459:
0460: /**
0461: * Foreign key linking the primary key columns to the superclass table,
0462: * or null if none.
0463: */
0464: public void setJoinForeignKey(ForeignKey fk) {
0465: _fk = fk;
0466: }
0467:
0468: public void refSchemaComponents() {
0469: if (getEmbeddingMetaData() == null) {
0470: if (_table != null && _table.getPrimaryKey() != null)
0471: _table.getPrimaryKey().ref();
0472: if (_fk != null)
0473: _fk.ref();
0474: Column[] pks = getPrimaryKeyColumns();
0475: for (int i = 0; i < pks.length; i++)
0476: pks[i].ref();
0477: } else {
0478: FieldMapping[] fields = getFieldMappings();
0479: for (int i = 0; i < fields.length; i++)
0480: fields[i].refSchemaComponents();
0481: }
0482: }
0483:
0484: /**
0485: * Clear mapping information, including strategy.
0486: */
0487: public void clearMapping() {
0488: _strategy = null;
0489: _cols = Schemas.EMPTY_COLUMNS;
0490: _fk = null;
0491: _table = null;
0492: _info.clear();
0493: setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
0494: }
0495:
0496: /**
0497: * Update {@link MappingInfo} with our current mapping information.
0498: */
0499: public void syncMappingInfo() {
0500: if (getEmbeddingMetaData() == null)
0501: _info.syncWith(this );
0502: else {
0503: _info.clear();
0504: FieldMapping[] fields = getFieldMappings();
0505: for (int i = 0; i < fields.length; i++)
0506: fields[i].syncMappingInfo();
0507: }
0508: }
0509:
0510: //////////////////////
0511: // MetaData interface
0512: //////////////////////
0513:
0514: protected void setDescribedType(Class type) {
0515: super .setDescribedType(type);
0516: // this method called from superclass constructor, so _info not yet
0517: // initialized
0518: if (_info != null)
0519: _info.setClassName(type.getName());
0520: }
0521:
0522: /**
0523: * The subclass fetch mode, as one of the eager constants in
0524: * {@link JDBCFetchConfiguration}.
0525: */
0526: public int getSubclassFetchMode() {
0527: if (_subclassMode == Integer.MAX_VALUE) {
0528: if (getPCSuperclass() != null)
0529: _subclassMode = getPCSuperclassMapping()
0530: .getSubclassFetchMode();
0531: else
0532: _subclassMode = FetchConfiguration.DEFAULT;
0533: }
0534: return _subclassMode;
0535: }
0536:
0537: /**
0538: * The subclass fetch mode, as one of the eager constants in
0539: * {@link JDBCFetchConfiguration}.
0540: */
0541: public void setSubclassFetchMode(int mode) {
0542: _subclassMode = mode;
0543: }
0544:
0545: /**
0546: * Convenience method to perform cast from
0547: * {@link ClassMetaData#getRepository}.
0548: */
0549: public MappingRepository getMappingRepository() {
0550: return (MappingRepository) getRepository();
0551: }
0552:
0553: /**
0554: * Convenience method to perform cast from
0555: * {@link ClassMetaData#getEmbeddingMetaData}
0556: */
0557: public ValueMapping getEmbeddingMapping() {
0558: return (ValueMapping) getEmbeddingMetaData();
0559: }
0560:
0561: /**
0562: * Returns true if this class does not use the "none" strategy (including
0563: * if it has a null strategy, and therefore is probably in the process of
0564: * being mapped).
0565: */
0566: public boolean isMapped() {
0567: if (!super .isMapped())
0568: return false;
0569: if (_strategy != null)
0570: return _strategy != NoneClassStrategy.getInstance();
0571: return !NoneClassStrategy.ALIAS.equals(_info.getStrategy());
0572: }
0573:
0574: /**
0575: * Convenience method to perform cast from
0576: * {@link ClassMetaData#getPCSuperclassMetaData}.
0577: */
0578: public ClassMapping getPCSuperclassMapping() {
0579: return (ClassMapping) getPCSuperclassMetaData();
0580: }
0581:
0582: /**
0583: * Convenience method to perform cast from
0584: * {@link ClassMetaData#getMappedPCSuperclassMetaData}.
0585: */
0586: public ClassMapping getMappedPCSuperclassMapping() {
0587: return (ClassMapping) getMappedPCSuperclassMetaData();
0588: }
0589:
0590: /**
0591: * Return the nearest mapped superclass that can join to this class.
0592: */
0593: public ClassMapping getJoinablePCSuperclassMapping() {
0594: ClassMapping sup = getMappedPCSuperclassMapping();
0595: if (sup == null)
0596: return null;
0597: if (_fk != null || _table == null
0598: || _table.equals(sup.getTable()))
0599: return sup;
0600: return null;
0601: }
0602:
0603: /**
0604: * Convenience method to perform cast from
0605: * {@link ClassMetaData#getPCSubclassMetaDatas}.
0606: */
0607: public ClassMapping[] getPCSubclassMappings() {
0608: return (ClassMapping[]) getPCSubclassMetaDatas();
0609: }
0610:
0611: /**
0612: * Convenience method to perform cast from
0613: * {@link ClassMetaData#getMappedPCSubclassMetaDatas}.
0614: */
0615: public ClassMapping[] getMappedPCSubclassMappings() {
0616: return (ClassMapping[]) getMappedPCSubclassMetaDatas();
0617: }
0618:
0619: /**
0620: * Return mapped subclasses that are reachable via joins.
0621: */
0622: public ClassMapping[] getJoinablePCSubclassMappings() {
0623: ClassMapping[] subs = getMappedPCSubclassMappings(); // checks for new
0624: if (_joinSubMaps == null) {
0625: if (subs.length == 0)
0626: _joinSubMaps = subs;
0627: else {
0628: List joinable = new ArrayList(subs.length);
0629: for (int i = 0; i < subs.length; i++)
0630: if (isSubJoinable(subs[i]))
0631: joinable.add(subs[i]);
0632: _joinSubMaps = (ClassMapping[]) joinable
0633: .toArray(new ClassMapping[joinable.size()]);
0634: }
0635: }
0636: return _joinSubMaps;
0637: }
0638:
0639: /**
0640: * Return whether we can reach the given subclass via joins.
0641: */
0642: private boolean isSubJoinable(ClassMapping sub) {
0643: if (sub == null)
0644: return false;
0645: if (sub == this )
0646: return true;
0647: return isSubJoinable(sub.getJoinablePCSuperclassMapping());
0648: }
0649:
0650: /**
0651: * Returns the closest-derived list of non-inter-joinable mapped types
0652: * assignable to this type. May return this mapping.
0653: */
0654: public ClassMapping[] getIndependentAssignableMappings() {
0655: ClassMapping[] subs = getMappedPCSubclassMappings(); // checks for new
0656: if (_assignMaps == null) {
0657: // remove unmapped subs
0658: if (subs.length == 0) {
0659: if (isMapped())
0660: _assignMaps = new ClassMapping[] { this };
0661: else
0662: _assignMaps = subs;
0663: } else {
0664: int size = (int) (subs.length * 1.33 + 2);
0665: Set independent = new LinkedHashSet(size);
0666: if (isMapped())
0667: independent.add(this );
0668: independent.addAll(Arrays.asList(subs));
0669:
0670: // remove all mappings that have a superclass mapping in the set
0671: ClassMapping map, sup;
0672: List clear = null;
0673: for (Iterator itr = independent.iterator(); itr
0674: .hasNext();) {
0675: map = (ClassMapping) itr.next();
0676: sup = map.getJoinablePCSuperclassMapping();
0677: if (sup != null && independent.contains(sup)) {
0678: if (clear == null)
0679: clear = new ArrayList(
0680: independent.size() - 1);
0681: clear.add(map);
0682: }
0683: }
0684: if (clear != null)
0685: independent.removeAll(clear);
0686:
0687: _assignMaps = (ClassMapping[]) independent
0688: .toArray(new ClassMapping[independent.size()]);
0689: }
0690: }
0691: return _assignMaps;
0692: }
0693:
0694: /**
0695: * Convenience method to perform cast from {@link ClassMetaData#getFields}.
0696: */
0697: public FieldMapping[] getFieldMappings() {
0698: return (FieldMapping[]) getFields();
0699: }
0700:
0701: /**
0702: * Convenience method to perform cast from
0703: * {@link ClassMetaData#getDeclaredFields}.
0704: */
0705: public FieldMapping[] getDeclaredFieldMappings() {
0706: return (FieldMapping[]) getDeclaredFields();
0707: }
0708:
0709: /**
0710: * Convenience method to perform cast from
0711: * {@link ClassMetaData#getPrimaryKeyFields}.
0712: */
0713: public FieldMapping[] getPrimaryKeyFieldMappings() {
0714: return (FieldMapping[]) getPrimaryKeyFields();
0715: }
0716:
0717: /**
0718: * Convenience method to perform cast from
0719: * {@link ClassMetaData#getVersionField}.
0720: */
0721: public FieldMapping getVersionFieldMapping() {
0722: return (FieldMapping) getVersionField();
0723: }
0724:
0725: /**
0726: * Convenience method to perform cast from
0727: * {@link ClassMetaData#getDefaultFetchGroupFields}.
0728: */
0729: public FieldMapping[] getDefaultFetchGroupFieldMappings() {
0730: return (FieldMapping[]) getDefaultFetchGroupFields();
0731: }
0732:
0733: /**
0734: * Convenience method to perform cast from
0735: * {@link ClassMetaData#getDefinedFields}.
0736: */
0737: public FieldMapping[] getDefinedFieldMappings() {
0738: return (FieldMapping[]) getDefinedFields();
0739: }
0740:
0741: /**
0742: * Convenience method to perform cast from
0743: * {@link ClassMetaData#getFieldsInListingOrder}.
0744: */
0745: public FieldMapping[] getFieldMappingsInListingOrder() {
0746: return (FieldMapping[]) getFieldsInListingOrder();
0747: }
0748:
0749: /**
0750: * Convenience method to perform cast from
0751: * {@link ClassMetaData#getDefinedFieldsInListingOrder}.
0752: */
0753: public FieldMapping[] getDefinedFieldMappingsInListingOrder() {
0754: return (FieldMapping[]) getDefinedFieldsInListingOrder();
0755: }
0756:
0757: /**
0758: * Convenience method to perform cast from {@link ClassMetaData#getField}.
0759: */
0760: public FieldMapping getFieldMapping(int index) {
0761: return (FieldMapping) getField(index);
0762: }
0763:
0764: /**
0765: * Convenience method to perform cast from
0766: * {@link ClassMetaData#getDeclaredField}.
0767: */
0768: public FieldMapping getDeclaredFieldMapping(int index) {
0769: return (FieldMapping) getDeclaredField(index);
0770: }
0771:
0772: /**
0773: * Convenience method to perform cast from {@link ClassMetaData#getField}.
0774: */
0775: public FieldMapping getFieldMapping(String name) {
0776: return (FieldMapping) getField(name);
0777: }
0778:
0779: /**
0780: * Convenience method to perform cast from
0781: * {@link ClassMetaData#getDeclaredField}.
0782: */
0783: public FieldMapping getDeclaredFieldMapping(String name) {
0784: return (FieldMapping) getDeclaredField(name);
0785: }
0786:
0787: /**
0788: * Convenience method to perform cast from
0789: * {@link ClassMetaData#getDeclaredUnmanagedFields}.
0790: */
0791: public FieldMapping[] getDeclaredUnmanagedFieldMappings() {
0792: return (FieldMapping[]) getDeclaredUnmanagedFields();
0793: }
0794:
0795: /**
0796: * Convenience method to perform cast from
0797: * {@link ClassMetaData#addDeclaredField}.
0798: */
0799: public FieldMapping addDeclaredFieldMapping(String name, Class type) {
0800: return (FieldMapping) addDeclaredField(name, type);
0801: }
0802:
0803: protected void resolveMapping(boolean runtime) {
0804: super .resolveMapping(runtime);
0805:
0806: // map class strategy; it may already be mapped by the repository before
0807: // the resolve process begins
0808: MappingRepository repos = getMappingRepository();
0809: if (_strategy == null)
0810: repos.getStrategyInstaller().installStrategy(this );
0811: Log log = getRepository().getLog();
0812: if (log.isTraceEnabled())
0813: log.trace(_loc.get("strategy", this , _strategy.getAlias()));
0814:
0815: // make sure unmapped superclass fields are defined if we're mapped;
0816: // also may have been done by repository already
0817: defineSuperclassFields(getJoinablePCSuperclassMapping() == null);
0818:
0819: // resolve everything that doesn't rely on any relations to avoid
0820: // recursion, then resolve all fields
0821: resolveNonRelationMappings();
0822: FieldMapping[] fms = getFieldMappings();
0823: for (int i = 0; i < fms.length; i++)
0824: if (fms[i].getDefiningMetaData() == this )
0825: fms[i].resolve(MODE_MAPPING);
0826: fms = getDeclaredUnmanagedFieldMappings();
0827: for (int i = 0; i < fms.length; i++)
0828: fms[i].resolve(MODE_MAPPING);
0829:
0830: // mark mapped columns
0831: if (_cols != null) {
0832: ColumnIO io = getColumnIO();
0833: for (int i = 0; i < _cols.length; i++) {
0834: if (io.isInsertable(i, false))
0835: _cols[i].setFlag(Column.FLAG_DIRECT_INSERT, true);
0836: if (io.isUpdatable(i, false))
0837: _cols[i].setFlag(Column.FLAG_DIRECT_UPDATE, true);
0838: }
0839: }
0840: // once columns are resolved, resolve unique constraints as they need
0841: // the columns be resolved
0842: _info.getUniques(this , true);
0843: }
0844:
0845: /**
0846: * Resolve non-relation field mappings so that when we do relation
0847: * mappings they can rely on them for joins.
0848: */
0849: void resolveNonRelationMappings() {
0850: // make sure primary key fields are resolved first because other
0851: // fields might rely on them
0852: FieldMapping[] fms = getPrimaryKeyFieldMappings();
0853: for (int i = 0; i < fms.length; i++)
0854: fms[i].resolve(MODE_MAPPING);
0855:
0856: // resolve defined fields that are safe; that don't rely on other types
0857: // also being resolved. don't use getDefinedFields b/c it relies on
0858: // whether fields are mapped, which isn't known yet
0859: fms = getFieldMappings();
0860: for (int i = 0; i < fms.length; i++)
0861: if (fms[i].getDefiningMetaData() == this
0862: && !fms[i].isTypePC()
0863: && !fms[i].getKey().isTypePC()
0864: && !fms[i].getElement().isTypePC())
0865: fms[i].resolve(MODE_MAPPING);
0866:
0867: _discrim.resolve(MODE_MAPPING);
0868: _version.resolve(MODE_MAPPING);
0869: }
0870:
0871: protected void initializeMapping() {
0872: super .initializeMapping();
0873:
0874: FieldMapping[] fields = getDefinedFieldMappings();
0875: for (int i = 0; i < fields.length; i++)
0876: fields[i].resolve(MODE_MAPPING_INIT);
0877: _discrim.resolve(MODE_MAPPING_INIT);
0878: _version.resolve(MODE_MAPPING_INIT);
0879: _strategy.initialize();
0880: }
0881:
0882: protected void clearDefinedFieldCache() {
0883: // just make this method available to other classes in this package
0884: super .clearDefinedFieldCache();
0885: }
0886:
0887: protected void clearSubclassCache() {
0888: super .clearSubclassCache();
0889: _joinSubMaps = null;
0890: _assignMaps = null;
0891: }
0892:
0893: public void copy(ClassMetaData cls) {
0894: super .copy(cls);
0895: if (_subclassMode == Integer.MAX_VALUE)
0896: _subclassMode = ((ClassMapping) cls).getSubclassFetchMode();
0897: }
0898:
0899: protected boolean validateDataStoreExtensionPrefix(String prefix) {
0900: return "jdbc-".equals(prefix);
0901: }
0902:
0903: ////////////////////////////////
0904: // ClassStrategy implementation
0905: ////////////////////////////////
0906:
0907: public String getAlias() {
0908: return assertStrategy().getAlias();
0909: }
0910:
0911: public void map(boolean adapt) {
0912: assertStrategy().map(adapt);
0913: }
0914:
0915: public void initialize() {
0916: assertStrategy().initialize();
0917: }
0918:
0919: public void insert(OpenJPAStateManager sm, JDBCStore store,
0920: RowManager rm) throws SQLException {
0921: assertStrategy().insert(sm, store, rm);
0922: }
0923:
0924: public void update(OpenJPAStateManager sm, JDBCStore store,
0925: RowManager rm) throws SQLException {
0926: assertStrategy().update(sm, store, rm);
0927: }
0928:
0929: public void delete(OpenJPAStateManager sm, JDBCStore store,
0930: RowManager rm) throws SQLException {
0931: assertStrategy().delete(sm, store, rm);
0932: }
0933:
0934: public Boolean isCustomInsert(OpenJPAStateManager sm,
0935: JDBCStore store) {
0936: return assertStrategy().isCustomInsert(sm, store);
0937: }
0938:
0939: public Boolean isCustomUpdate(OpenJPAStateManager sm,
0940: JDBCStore store) {
0941: return assertStrategy().isCustomUpdate(sm, store);
0942: }
0943:
0944: public Boolean isCustomDelete(OpenJPAStateManager sm,
0945: JDBCStore store) {
0946: return assertStrategy().isCustomDelete(sm, store);
0947: }
0948:
0949: public void customInsert(OpenJPAStateManager sm, JDBCStore store)
0950: throws SQLException {
0951: assertStrategy().customInsert(sm, store);
0952: }
0953:
0954: public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
0955: throws SQLException {
0956: assertStrategy().customUpdate(sm, store);
0957: }
0958:
0959: public void customDelete(OpenJPAStateManager sm, JDBCStore store)
0960: throws SQLException {
0961: assertStrategy().customDelete(sm, store);
0962: }
0963:
0964: public void setClassMapping(ClassMapping owner) {
0965: assertStrategy().setClassMapping(owner);
0966: }
0967:
0968: public boolean isPrimaryKeyObjectId(boolean hasAll) {
0969: return assertStrategy().isPrimaryKeyObjectId(hasAll);
0970: }
0971:
0972: public Joins joinSuperclass(Joins joins, boolean toThis) {
0973: return assertStrategy().joinSuperclass(joins, toThis);
0974: }
0975:
0976: public boolean supportsEagerSelect(Select sel,
0977: OpenJPAStateManager sm, JDBCStore store, ClassMapping base,
0978: JDBCFetchConfiguration fetch) {
0979: return assertStrategy().supportsEagerSelect(sel, sm, store,
0980: base, fetch);
0981: }
0982:
0983: public ResultObjectProvider customLoad(JDBCStore store,
0984: boolean subclasses, JDBCFetchConfiguration fetch,
0985: long startIdx, long endIdx) throws SQLException {
0986: return assertStrategy().customLoad(store, subclasses, fetch,
0987: startIdx, endIdx);
0988: }
0989:
0990: public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
0991: PCState state, JDBCFetchConfiguration fetch)
0992: throws SQLException, ClassNotFoundException {
0993: return assertStrategy().customLoad(sm, store, state, fetch);
0994: }
0995:
0996: public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
0997: JDBCFetchConfiguration fetch, Result result)
0998: throws SQLException {
0999: return assertStrategy().customLoad(sm, store, fetch, result);
1000: }
1001:
1002: private ClassStrategy assertStrategy() {
1003: if (_strategy == null)
1004: throw new InternalException();
1005: return _strategy;
1006: }
1007: }
|