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:
0023: import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
0024: import org.apache.openjpa.jdbc.kernel.JDBCStore;
0025: import org.apache.openjpa.jdbc.meta.strats.NoneFieldStrategy;
0026: import org.apache.openjpa.jdbc.schema.Column;
0027: import org.apache.openjpa.jdbc.schema.ColumnIO;
0028: import org.apache.openjpa.jdbc.schema.ForeignKey;
0029: import org.apache.openjpa.jdbc.schema.Index;
0030: import org.apache.openjpa.jdbc.schema.Table;
0031: import org.apache.openjpa.jdbc.schema.Unique;
0032: import org.apache.openjpa.jdbc.sql.Joins;
0033: import org.apache.openjpa.jdbc.sql.Result;
0034: import org.apache.openjpa.jdbc.sql.Row;
0035: import org.apache.openjpa.jdbc.sql.RowManager;
0036: import org.apache.openjpa.jdbc.sql.SQLBuffer;
0037: import org.apache.openjpa.jdbc.sql.Select;
0038: import org.apache.openjpa.jdbc.sql.SelectExecutor;
0039: import org.apache.openjpa.kernel.FetchConfiguration;
0040: import org.apache.openjpa.kernel.OpenJPAStateManager;
0041: import org.apache.openjpa.lib.log.Log;
0042: import org.apache.openjpa.lib.util.Localizer;
0043: import org.apache.openjpa.meta.FieldMetaData;
0044: import org.apache.openjpa.meta.JavaTypes;
0045: import org.apache.openjpa.util.InternalException;
0046: import org.apache.openjpa.util.MetaDataException;
0047:
0048: /**
0049: * Specialization of metadata for relational databases.
0050: *
0051: * @author Abe White
0052: */
0053: public class FieldMapping extends FieldMetaData implements
0054: ValueMapping, FieldStrategy {
0055:
0056: private static final Localizer _loc = Localizer
0057: .forPackage(FieldMapping.class);
0058:
0059: private final ValueMapping _val;
0060: private final ValueMapping _key;
0061: private final ValueMapping _elem;
0062: private final FieldMappingInfo _info;
0063: private final JDBCColumnOrder _orderCol = new JDBCColumnOrder();
0064: private FieldStrategy _strategy = null;
0065:
0066: private ForeignKey _fk = null;
0067: private ColumnIO _io = null;
0068: private Unique _unq = null;
0069: private Index _idx = null;
0070: private boolean _outer = false;
0071: private int _fetchMode = Integer.MAX_VALUE;
0072:
0073: /**
0074: * Constructor.
0075: */
0076: public FieldMapping(String name, Class type, ClassMapping owner) {
0077: super (name, type, owner);
0078: _info = owner.getMappingRepository().newMappingInfo(this );
0079: _val = (ValueMapping) getValue();
0080: _key = (ValueMapping) getKey();
0081: _elem = (ValueMapping) getElement();
0082:
0083: setUsesIntermediate(false);
0084: setUsesImplData(Boolean.FALSE);
0085: }
0086:
0087: ///////
0088: // ORM
0089: ///////
0090:
0091: /**
0092: * Raw mapping data about field's join to parent table, as well as
0093: * miscellaneous specialized columns like order column.
0094: */
0095: public FieldMappingInfo getMappingInfo() {
0096: return _info;
0097: }
0098:
0099: /**
0100: * The strategy used to map this mapping.
0101: */
0102: public FieldStrategy getStrategy() {
0103: return _strategy;
0104: }
0105:
0106: /**
0107: * The strategy used to map this mapping. The <code>adapt</code>
0108: * parameter determines whether to adapt when mapping the strategy;
0109: * use null if the strategy should not be mapped.
0110: */
0111: public void setStrategy(FieldStrategy strategy, Boolean adapt) {
0112: // set strategy first so we can access it during mapping
0113: FieldStrategy orig = _strategy;
0114: _strategy = strategy;
0115: if (strategy != null) {
0116: try {
0117: strategy.setFieldMapping(this );
0118: if (adapt != null)
0119: strategy.map(adapt.booleanValue());
0120: } catch (RuntimeException re) {
0121: // reset strategy
0122: _strategy = orig;
0123: throw re;
0124: }
0125:
0126: // if set to unmapped, clear defined field cache in parent
0127: if (!isMapped())
0128: getDefiningMapping().clearDefinedFieldCache();
0129: }
0130: }
0131:
0132: /**
0133: * The mapping's primary table.
0134: */
0135: public Table getTable() {
0136: if (_fk != null)
0137: return _fk.getTable();
0138: if (_val.getForeignKey() != null)
0139: return _val.getForeignKey().getTable();
0140: return getDefiningMapping().getTable();
0141: }
0142:
0143: /**
0144: * I/O information on the join columns.
0145: */
0146: public ColumnIO getJoinColumnIO() {
0147: return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
0148: }
0149:
0150: /**
0151: * I/O information on the join columns.
0152: */
0153: public void setJoinColumnIO(ColumnIO io) {
0154: _io = io;
0155: }
0156:
0157: /**
0158: * Foreign key linking the field table to the class' primary table.
0159: */
0160: public ForeignKey getJoinForeignKey() {
0161: return _fk;
0162: }
0163:
0164: /**
0165: * Foreign key linking the field table to the class' primary table.
0166: */
0167: public void setJoinForeignKey(ForeignKey fk) {
0168: _fk = fk;
0169: }
0170:
0171: /**
0172: * Unique constraint on join foreign key columns.
0173: */
0174: public Unique getJoinUnique() {
0175: return _unq;
0176: }
0177:
0178: /**
0179: * Unique constraint on join foreign key columns.
0180: */
0181: public void setJoinUnique(Unique unq) {
0182: _unq = unq;
0183: }
0184:
0185: /**
0186: * Index on join foreign key columns.
0187: */
0188: public Index getJoinIndex() {
0189: return _idx;
0190: }
0191:
0192: /**
0193: * Index on join foreign key columns.
0194: */
0195: public void setJoinIndex(Index idx) {
0196: _idx = idx;
0197: }
0198:
0199: /**
0200: * Whether to use an outer join from the class' primary table.
0201: */
0202: public boolean isJoinOuter() {
0203: return _outer;
0204: }
0205:
0206: /**
0207: * Whether to use an outer join from the class' primary table.
0208: */
0209: public void setJoinOuter(boolean outer) {
0210: _outer = outer;
0211: }
0212:
0213: /**
0214: * Field order column, if any.
0215: */
0216: public Column getOrderColumn() {
0217: return _orderCol.getColumn();
0218: }
0219:
0220: /**
0221: * Field order column, if any.
0222: */
0223: public void setOrderColumn(Column order) {
0224: _orderCol.setColumn(order);
0225: }
0226:
0227: /**
0228: * I/O information for order column.
0229: */
0230: public ColumnIO getOrderColumnIO() {
0231: return _orderCol.getColumnIO();
0232: }
0233:
0234: /**
0235: * I/O information for order column.
0236: */
0237: public void setOrderColumnIO(ColumnIO io) {
0238: _orderCol.setColumnIO(io);
0239: }
0240:
0241: /**
0242: * Increment the reference count of used schema components.
0243: */
0244: public void refSchemaComponents() {
0245: if (_fk != null) {
0246: _fk.ref();
0247: _fk.refColumns();
0248: }
0249: if (_orderCol.getColumn() != null)
0250: _orderCol.getColumn().ref();
0251: _val.refSchemaComponents();
0252: _key.refSchemaComponents();
0253: _elem.refSchemaComponents();
0254: }
0255:
0256: /**
0257: * Clear mapping information, including strategy.
0258: */
0259: public void clearMapping() {
0260: _strategy = null;
0261: _fk = null;
0262: _unq = null;
0263: _idx = null;
0264: _outer = false;
0265: _orderCol.setColumn(null);
0266: _val.clearMapping();
0267: _key.clearMapping();
0268: _elem.clearMapping();
0269: _info.clear();
0270: setResolve(MODE_MAPPING, false);
0271: }
0272:
0273: /**
0274: * Update {@link MappingInfo} with our current mapping information.
0275: */
0276: public void syncMappingInfo() {
0277: if (isVersion()) {
0278: // we rely on the fact that the version will setup our mapping
0279: // info correctly when it is synced
0280: } else if (getMappedByMapping() != null) {
0281: _info.clear();
0282: _val.getValueInfo().clear();
0283: _key.getValueInfo().clear();
0284: _elem.getValueInfo().clear();
0285:
0286: FieldMapping mapped = getMappedByMapping();
0287: _info.syncStrategy(this );
0288: if (_orderCol.getColumn() != null
0289: && mapped.getOrderColumn() == null)
0290: _info.syncOrderColumn(this );
0291: _val.getValueInfo().setUseClassCriteria(
0292: _val.getUseClassCriteria());
0293: _key.getValueInfo().setUseClassCriteria(
0294: _key.getUseClassCriteria());
0295: _elem.getValueInfo().setUseClassCriteria(
0296: _elem.getUseClassCriteria());
0297: } else {
0298: _info.syncWith(this );
0299: _val.syncMappingInfo();
0300: _key.syncMappingInfo();
0301: _elem.syncMappingInfo();
0302: }
0303: }
0304:
0305: /**
0306: * Returns true if field class does not use the "none" strategy (including
0307: * if it has a null strategy, and therefore is probably in the process of
0308: * being mapped).
0309: */
0310: public boolean isMapped() {
0311: return _strategy != NoneFieldStrategy.getInstance();
0312: }
0313:
0314: //////////////////////
0315: // MetaData interface
0316: //////////////////////
0317:
0318: /**
0319: * The eager fetch mode, as one of the eager constants in
0320: * {@link JDBCFetchConfiguration}.
0321: */
0322: public int getEagerFetchMode() {
0323: if (_fetchMode == Integer.MAX_VALUE)
0324: _fetchMode = FetchConfiguration.DEFAULT;
0325: return _fetchMode;
0326: }
0327:
0328: /**
0329: * The eager fetch mode, as one of the eager constants in
0330: * {@link JDBCFetchConfiguration}.
0331: */
0332: public void setEagerFetchMode(int mode) {
0333: _fetchMode = mode;
0334: }
0335:
0336: /**
0337: * Convenience method to perform cast from
0338: * {@link FieldMetaData#getRepository}
0339: */
0340: public MappingRepository getMappingRepository() {
0341: return (MappingRepository) getRepository();
0342: }
0343:
0344: /**
0345: * Convenience method to perform cast from
0346: * {@link FieldMetaData#getDefiningMetaData}
0347: */
0348: public ClassMapping getDefiningMapping() {
0349: return (ClassMapping) getDefiningMetaData();
0350: }
0351:
0352: /**
0353: * Convenience method to perform cast from
0354: * {@link FieldMetaData#getDeclaringMetaData}
0355: */
0356: public ClassMapping getDeclaringMapping() {
0357: return (ClassMapping) getDeclaringMetaData();
0358: }
0359:
0360: /**
0361: * Convenience method to perform cast from {@link FieldMetaData#getKey}
0362: */
0363: public ValueMapping getKeyMapping() {
0364: return _key;
0365: }
0366:
0367: /**
0368: * Convenience method to perform cast from {@link FieldMetaData#getElement}
0369: */
0370: public ValueMapping getElementMapping() {
0371: return _elem;
0372: }
0373:
0374: /**
0375: * Convenience method to perform cast from {@link FieldMetaData#getValue}
0376: */
0377: public ValueMapping getValueMapping() {
0378: return (ValueMapping) getValue();
0379: }
0380:
0381: /**
0382: * Convenience method to perform cast from
0383: * {@link FieldMetaData#getMappedByMetaData}
0384: */
0385: public FieldMapping getMappedByMapping() {
0386: return (FieldMapping) getMappedByMetaData();
0387: }
0388:
0389: /**
0390: * Convenience method to perform cast from
0391: * {@link FieldMetaData#getInverseMetaDatas}
0392: */
0393: public FieldMapping[] getInverseMappings() {
0394: return (FieldMapping[]) getInverseMetaDatas();
0395: }
0396:
0397: public boolean resolve(int mode) {
0398: int cur = getResolve();
0399: if (super .resolve(mode))
0400: return true;
0401: if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
0402: resolveMapping();
0403: if ((mode & MODE_MAPPING_INIT) != 0
0404: && (cur & MODE_MAPPING_INIT) == 0)
0405: initializeMapping();
0406: return false;
0407: }
0408:
0409: /**
0410: * Resolve the mapping information for this field.
0411: */
0412: private void resolveMapping() {
0413: MappingRepository repos = getMappingRepository();
0414: if (repos.getMappingDefaults().defaultMissingInfo()) {
0415: // copy embedded template mapping info
0416: ClassMapping cls = getDefiningMapping();
0417: if (cls.getEmbeddingMapping() != null) {
0418: ClassMapping orig = repos.getMapping(cls
0419: .getDescribedType(), cls.getEnvClassLoader(),
0420: true);
0421: FieldMapping tmplate = orig.getFieldMapping(getName());
0422: if (tmplate != null)
0423: copyMappingInfo(tmplate);
0424: }
0425: // copy superclass field info
0426: else if (cls.isMapped() && cls.getPCSuperclass() != null
0427: && cls.getDescribedType() != getDeclaringType()) {
0428: FieldMapping sup = cls.getPCSuperclassMapping()
0429: .getFieldMapping(getName());
0430: if (sup != null)
0431: copyMappingInfo(sup);
0432: }
0433: }
0434:
0435: if (_strategy == null) {
0436: if (isVersion())
0437: _strategy = NoneFieldStrategy.getInstance();
0438: else
0439: repos.getStrategyInstaller().installStrategy(this );
0440: }
0441: Log log = getRepository().getLog();
0442: if (log.isTraceEnabled())
0443: log.trace(_loc.get("field-strategy", getName(), _strategy
0444: .getAlias()));
0445:
0446: // mark mapped columns
0447: if (_orderCol.getColumn() != null) {
0448: if (getOrderColumnIO().isInsertable(0, false))
0449: _orderCol.getColumn().setFlag(
0450: Column.FLAG_DIRECT_INSERT, true);
0451: if (getOrderColumnIO().isUpdatable(0, false))
0452: _orderCol.getColumn().setFlag(
0453: Column.FLAG_DIRECT_UPDATE, true);
0454: }
0455: if (_fk != null) {
0456: Column[] cols = _fk.getColumns();
0457: ColumnIO io = getJoinColumnIO();
0458: for (int i = 0; i < cols.length; i++) {
0459: if (io.isInsertable(i, false))
0460: cols[i].setFlag(Column.FLAG_FK_INSERT, true);
0461: if (io.isUpdatable(i, false))
0462: cols[i].setFlag(Column.FLAG_FK_UPDATE, true);
0463: }
0464: }
0465:
0466: _val.resolve(MODE_MAPPING);
0467: _key.resolve(MODE_MAPPING);
0468: _elem.resolve(MODE_MAPPING);
0469: }
0470:
0471: /**
0472: * Copy mapping info from the given instance to this one.
0473: */
0474: public void copyMappingInfo(FieldMapping fm) {
0475: setMappedBy(fm.getMappedBy());
0476: _info.copy(fm.getMappingInfo());
0477: _val.copyMappingInfo(fm.getValueMapping());
0478: _key.copyMappingInfo(fm.getKeyMapping());
0479: _elem.copyMappingInfo(fm.getElementMapping());
0480: }
0481:
0482: /**
0483: * Prepare mapping for runtime use.
0484: */
0485: private void initializeMapping() {
0486: _val.resolve(MODE_MAPPING_INIT);
0487: _key.resolve(MODE_MAPPING_INIT);
0488: _val.resolve(MODE_MAPPING_INIT);
0489: if (_strategy != null)
0490: _strategy.initialize();
0491: }
0492:
0493: public void copy(FieldMetaData fmd) {
0494: super .copy(fmd);
0495: if (_fetchMode == Integer.MAX_VALUE)
0496: _fetchMode = ((FieldMapping) fmd).getEagerFetchMode();
0497: }
0498:
0499: protected boolean validateDataStoreExtensionPrefix(String prefix) {
0500: return "jdbc-".equals(prefix);
0501: }
0502:
0503: ////////////////////////////////
0504: // FieldStrategy implementation
0505: ////////////////////////////////
0506:
0507: public String getAlias() {
0508: return assertStrategy().getAlias();
0509: }
0510:
0511: public void map(boolean adapt) {
0512: assertStrategy().map(adapt);
0513: }
0514:
0515: /**
0516: * Map this field to its table, optionally requiring that it be
0517: * in another table. Utility method for use by mapping strategies.
0518: */
0519: public void mapJoin(boolean adapt, boolean joinRequired) {
0520: Table table = _info.getTable(this , joinRequired, adapt);
0521:
0522: if (table != null
0523: && table.equals(getDefiningMapping().getTable())) {
0524: // Don't create a join if the field's table is the same as the
0525: // class's table.
0526: table = null;
0527: }
0528:
0529: ForeignKey join = null;
0530: if (table != null)
0531: join = _info.getJoin(this , table, adapt);
0532: if (join == null && joinRequired)
0533: throw new MetaDataException(_loc.get("join-required", this ));
0534:
0535: if (join == null) {
0536: _info.assertNoJoin(this , true);
0537: _info.assertNoForeignKey(this , !adapt);
0538: _info.assertNoUnique(this , !adapt);
0539: _info.assertNoIndex(this , !adapt);
0540: } else {
0541: _fk = join;
0542: _io = _info.getColumnIO();
0543: _outer = _info.isJoinOuter();
0544: _unq = _info.getJoinUnique(this , false, adapt);
0545: _idx = _info.getJoinIndex(this , adapt);
0546: }
0547: }
0548:
0549: /**
0550: * Maps the primary key on the secondary table for this field, if the
0551: * user's defaults create one. This must be called after
0552: * this field is mapped so that it's table has its columns set.
0553: */
0554: public void mapPrimaryKey(boolean adapt) {
0555: if (adapt && _fk != null
0556: && _fk.getTable().getPrimaryKey() == null)
0557: getMappingRepository().getMappingDefaults()
0558: .installPrimaryKey(this , _fk.getTable());
0559: }
0560:
0561: public void initialize() {
0562: assertStrategy().initialize();
0563: }
0564:
0565: public void insert(OpenJPAStateManager sm, JDBCStore store,
0566: RowManager rm) throws SQLException {
0567: assertStrategy().insert(sm, store, rm);
0568: }
0569:
0570: public void update(OpenJPAStateManager sm, JDBCStore store,
0571: RowManager rm) throws SQLException {
0572: assertStrategy().update(sm, store, rm);
0573: }
0574:
0575: public void delete(OpenJPAStateManager sm, JDBCStore store,
0576: RowManager rm) throws SQLException {
0577: assertStrategy().delete(sm, store, rm);
0578: }
0579:
0580: /**
0581: * Delete the row for this object if the reference foreign key exists.
0582: * Utility method for use by mapping strategies.
0583: */
0584: public void deleteRow(OpenJPAStateManager sm, JDBCStore store,
0585: RowManager rm) throws SQLException {
0586: if (_fk != null) {
0587: Row row = rm
0588: .getRow(getTable(), Row.ACTION_DELETE, sm, true);
0589: row.whereForeignKey(_fk, sm);
0590: }
0591: }
0592:
0593: /**
0594: * Return the row to use for this field. This method is meant only for
0595: * single-value fields that might reside in a table that is joined to
0596: * the primary table through the join foreign key. It is not
0597: * meant for multi-valued fields like collections and maps. The method
0598: * checks whether we're using an outer join and if so it deletes the
0599: * field's previous value, then if the field is non-null returns an insert
0600: * row for the new value. The join foreign key will already be set on
0601: * the returned row; mapping strategies just need to set their own values.
0602: * Utility method for use by mapping strategies.
0603: */
0604: public Row getRow(OpenJPAStateManager sm, JDBCStore store,
0605: RowManager rm, int action) throws SQLException {
0606: Row row = null;
0607: boolean newOuterRow = false;
0608: if (_fk != null && _outer && action != Row.ACTION_DELETE) {
0609: // if updating with outer join, delete old value first, then insert;
0610: // we can't just update b/c the row might not exist
0611: if (action == Row.ACTION_UPDATE) {
0612: // maybe some other field already is updating?
0613: row = rm.getRow(getTable(), Row.ACTION_UPDATE, sm,
0614: false);
0615: if (row == null) {
0616: Row del = rm.getRow(getTable(), Row.ACTION_DELETE,
0617: sm, true);
0618: del.whereForeignKey(_fk, sm);
0619: }
0620: } else
0621: row = rm.getRow(getTable(), Row.ACTION_INSERT, sm,
0622: false);
0623:
0624: // only update/insert if the row exists already or the value is
0625: // not null/default
0626: if (row == null && !isNullValue(sm)) {
0627: row = rm
0628: .getRow(getTable(), Row.ACTION_INSERT, sm, true);
0629: newOuterRow = true;
0630: }
0631: } else
0632: row = rm.getRow(getTable(), action, sm, true);
0633:
0634: // setup fk
0635: if (row != null && _fk != null) {
0636: if (row.getAction() == Row.ACTION_INSERT)
0637: row.setForeignKey(_fk, _io, sm);
0638: else
0639: row.whereForeignKey(_fk, sm);
0640:
0641: // if this is a new outer joined row, mark it invalid until
0642: // some mapping actually sets information on it
0643: if (newOuterRow)
0644: row.setValid(false);
0645: }
0646: return row;
0647: }
0648:
0649: /**
0650: * Return true if this field is null/default in the given instance.
0651: */
0652: private boolean isNullValue(OpenJPAStateManager sm) {
0653: switch (getTypeCode()) {
0654: case JavaTypes.BOOLEAN:
0655: return !sm.fetchBoolean(getIndex());
0656: case JavaTypes.BYTE:
0657: return sm.fetchByte(getIndex()) == 0;
0658: case JavaTypes.CHAR:
0659: return sm.fetchChar(getIndex()) == 0;
0660: case JavaTypes.DOUBLE:
0661: return sm.fetchDouble(getIndex()) == 0;
0662: case JavaTypes.FLOAT:
0663: return sm.fetchFloat(getIndex()) == 0;
0664: case JavaTypes.INT:
0665: return sm.fetchInt(getIndex()) == 0;
0666: case JavaTypes.LONG:
0667: return sm.fetchLong(getIndex()) == 0;
0668: case JavaTypes.SHORT:
0669: return sm.fetchShort(getIndex()) == 0;
0670: case JavaTypes.STRING:
0671: return sm.fetchString(getIndex()) == null;
0672: default:
0673: return sm.fetchObject(getIndex()) == null;
0674: }
0675: }
0676:
0677: public Boolean isCustomInsert(OpenJPAStateManager sm,
0678: JDBCStore store) {
0679: return assertStrategy().isCustomInsert(sm, store);
0680: }
0681:
0682: public Boolean isCustomUpdate(OpenJPAStateManager sm,
0683: JDBCStore store) {
0684: return assertStrategy().isCustomUpdate(sm, store);
0685: }
0686:
0687: public Boolean isCustomDelete(OpenJPAStateManager sm,
0688: JDBCStore store) {
0689: return assertStrategy().isCustomDelete(sm, store);
0690: }
0691:
0692: public void customInsert(OpenJPAStateManager sm, JDBCStore store)
0693: throws SQLException {
0694: assertStrategy().customInsert(sm, store);
0695: }
0696:
0697: public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
0698: throws SQLException {
0699: assertStrategy().customUpdate(sm, store);
0700: }
0701:
0702: public void customDelete(OpenJPAStateManager sm, JDBCStore store)
0703: throws SQLException {
0704: assertStrategy().customDelete(sm, store);
0705: }
0706:
0707: public void setFieldMapping(FieldMapping owner) {
0708: assertStrategy().setFieldMapping(owner);
0709: }
0710:
0711: public int supportsSelect(Select sel, int type,
0712: OpenJPAStateManager sm, JDBCStore store,
0713: JDBCFetchConfiguration fetch) {
0714: return assertStrategy().supportsSelect(sel, type, sm, store,
0715: fetch);
0716: }
0717:
0718: public void selectEagerParallel(SelectExecutor sel,
0719: OpenJPAStateManager sm, JDBCStore store,
0720: JDBCFetchConfiguration fetch, int eagerMode) {
0721: assertStrategy().selectEagerParallel(sel, sm, store, fetch,
0722: eagerMode);
0723: }
0724:
0725: public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
0726: JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
0727: assertStrategy().selectEagerJoin(sel, sm, store, fetch,
0728: eagerMode);
0729: }
0730:
0731: public boolean isEagerSelectToMany() {
0732: return assertStrategy().isEagerSelectToMany();
0733: }
0734:
0735: public int select(Select sel, OpenJPAStateManager sm,
0736: JDBCStore store, JDBCFetchConfiguration fetch, int eagerMode) {
0737: return assertStrategy()
0738: .select(sel, sm, store, fetch, eagerMode);
0739: }
0740:
0741: /**
0742: * Return any joins needed to get from the primary table to this table.
0743: */
0744: public Joins join(Select sel) {
0745: if (_fk == null)
0746: return null;
0747:
0748: Joins joins = sel.newJoins();
0749: if (_outer)
0750: return joins.outerJoin(_fk, true, false);
0751: return joins.join(_fk, true, false);
0752: }
0753:
0754: /**
0755: * Add a <code>wherePrimaryKey</code> or <code>whereForeignKey</code>
0756: * condition to the given select, depending on whether we have a join
0757: * foreign key.
0758: */
0759: public void wherePrimaryKey(Select sel, OpenJPAStateManager sm,
0760: JDBCStore store) {
0761: if (_fk != null)
0762: sel.whereForeignKey(_fk, sm.getObjectId(),
0763: getDefiningMapping(), store);
0764: else
0765: sel.wherePrimaryKey(sm.getObjectId(), getDefiningMapping(),
0766: store);
0767: }
0768:
0769: /**
0770: * Add ordering to the given select for all non-relation order values,
0771: * including the synthetic order column, if any.
0772: *
0773: * @param elem the related type we're fetching, or null
0774: * @param joins the joins to this field's table
0775: */
0776: public void orderLocal(Select sel, ClassMapping elem, Joins joins) {
0777: _orderCol.order(sel, elem, joins);
0778: JDBCOrder[] orders = (JDBCOrder[]) getOrders();
0779: for (int i = 0; i < orders.length; i++)
0780: if (!orders[i].isInRelation())
0781: orders[i].order(sel, elem, joins);
0782: }
0783:
0784: /**
0785: * Add ordering to the given select for all relation-based values.
0786: *
0787: * @param elem the related type we're fetching
0788: * @param joins the joins across the relation
0789: */
0790: public void orderRelation(Select sel, ClassMapping elem, Joins joins) {
0791: JDBCOrder[] orders = (JDBCOrder[]) getOrders();
0792: for (int i = 0; i < orders.length; i++)
0793: if (orders[i].isInRelation())
0794: orders[i].order(sel, elem, joins);
0795: }
0796:
0797: public Object loadEagerParallel(OpenJPAStateManager sm,
0798: JDBCStore store, JDBCFetchConfiguration fetch, Object res)
0799: throws SQLException {
0800: return assertStrategy()
0801: .loadEagerParallel(sm, store, fetch, res);
0802: }
0803:
0804: public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
0805: JDBCFetchConfiguration fetch, Result res)
0806: throws SQLException {
0807: assertStrategy().loadEagerJoin(sm, store, fetch, res);
0808: }
0809:
0810: public void load(OpenJPAStateManager sm, JDBCStore store,
0811: JDBCFetchConfiguration fetch, Result res)
0812: throws SQLException {
0813: assertStrategy().load(sm, store, fetch, res);
0814: }
0815:
0816: public void load(OpenJPAStateManager sm, JDBCStore store,
0817: JDBCFetchConfiguration fetch) throws SQLException {
0818: assertStrategy().load(sm, store, fetch);
0819: }
0820:
0821: public Object toDataStoreValue(Object val, JDBCStore store) {
0822: return assertStrategy().toDataStoreValue(val, store);
0823: }
0824:
0825: public Object toKeyDataStoreValue(Object val, JDBCStore store) {
0826: return assertStrategy().toKeyDataStoreValue(val, store);
0827: }
0828:
0829: public void appendIsEmpty(SQLBuffer sql, Select sel, Joins joins) {
0830: assertStrategy().appendIsEmpty(sql, sel, joins);
0831: }
0832:
0833: public void appendIsNotEmpty(SQLBuffer sql, Select sel, Joins joins) {
0834: assertStrategy().appendIsNotEmpty(sql, sel, joins);
0835: }
0836:
0837: public void appendIsNull(SQLBuffer sql, Select sel, Joins joins) {
0838: assertStrategy().appendIsNull(sql, sel, joins);
0839: }
0840:
0841: public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) {
0842: assertStrategy().appendIsNotNull(sql, sel, joins);
0843: }
0844:
0845: public void appendSize(SQLBuffer sql, Select sel, Joins joins) {
0846: assertStrategy().appendSize(sql, sel, joins);
0847: }
0848:
0849: public Joins join(Joins joins, boolean forceOuter) {
0850: return assertStrategy().join(joins, forceOuter);
0851: }
0852:
0853: public Joins joinKey(Joins joins, boolean forceOuter) {
0854: return assertStrategy().joinKey(joins, forceOuter);
0855: }
0856:
0857: public Joins joinRelation(Joins joins, boolean forceOuter,
0858: boolean traverse) {
0859: return assertStrategy().joinRelation(joins, forceOuter,
0860: traverse);
0861: }
0862:
0863: public Joins joinKeyRelation(Joins joins, boolean forceOuter,
0864: boolean traverse) {
0865: return assertStrategy().joinKeyRelation(joins, forceOuter,
0866: traverse);
0867: }
0868:
0869: /**
0870: * Joins from the owning class' table to the table where this field lies
0871: * using the join foreign key. Utility method for use by mapping strategies.
0872: */
0873: public Joins join(Joins joins, boolean forceOuter, boolean toMany) {
0874: if (_fk == null)
0875: return joins;
0876: if (_outer || forceOuter)
0877: return joins.outerJoin(_fk, true, toMany);
0878: return joins.join(_fk, true, toMany);
0879: }
0880:
0881: public Object loadProjection(JDBCStore store,
0882: JDBCFetchConfiguration fetch, Result res, Joins joins)
0883: throws SQLException {
0884: return assertStrategy()
0885: .loadProjection(store, fetch, res, joins);
0886: }
0887:
0888: public Object loadKeyProjection(JDBCStore store,
0889: JDBCFetchConfiguration fetch, Result res, Joins joins)
0890: throws SQLException {
0891: return assertStrategy().loadKeyProjection(store, fetch, res,
0892: joins);
0893: }
0894:
0895: public boolean isVersionable() {
0896: return assertStrategy().isVersionable();
0897: }
0898:
0899: public void where(OpenJPAStateManager sm, JDBCStore store,
0900: RowManager rm, Object prevValue) throws SQLException {
0901: assertStrategy().where(sm, store, rm, prevValue);
0902: }
0903:
0904: private FieldStrategy assertStrategy() {
0905: if (_strategy == null)
0906: throw new InternalException();
0907: return _strategy;
0908: }
0909:
0910: ///////////////////////////////
0911: // ValueMapping implementation
0912: ///////////////////////////////
0913:
0914: public ValueMappingInfo getValueInfo() {
0915: return _val.getValueInfo();
0916: }
0917:
0918: public ValueHandler getHandler() {
0919: return _val.getHandler();
0920: }
0921:
0922: public void setHandler(ValueHandler handler) {
0923: _val.setHandler(handler);
0924: }
0925:
0926: public FieldMapping getFieldMapping() {
0927: return this ;
0928: }
0929:
0930: public ClassMapping getTypeMapping() {
0931: return _val.getTypeMapping();
0932: }
0933:
0934: public ClassMapping getDeclaredTypeMapping() {
0935: return _val.getDeclaredTypeMapping();
0936: }
0937:
0938: public ClassMapping getEmbeddedMapping() {
0939: return _val.getEmbeddedMapping();
0940: }
0941:
0942: public FieldMapping getValueMappedByMapping() {
0943: return _val.getValueMappedByMapping();
0944: }
0945:
0946: public Column[] getColumns() {
0947: // pcl: 6 July 2007: this seems a bit hacky, but if the mapping is a
0948: // version, it will have a NoneFieldMapping (since the version strategy
0949: // for the class takes care of it's mapping), and NoneFieldStrategies
0950: // do not have columns.
0951: if (isVersion())
0952: return getDeclaringMapping().getVersion().getColumns();
0953: else
0954: return _val.getColumns();
0955: }
0956:
0957: public void setColumns(Column[] cols) {
0958: _val.setColumns(cols);
0959: }
0960:
0961: public ColumnIO getColumnIO() {
0962: return _val.getColumnIO();
0963: }
0964:
0965: public void setColumnIO(ColumnIO io) {
0966: _val.setColumnIO(io);
0967: }
0968:
0969: public ForeignKey getForeignKey() {
0970: return _val.getForeignKey();
0971: }
0972:
0973: public ForeignKey getForeignKey(ClassMapping target) {
0974: return _val.getForeignKey(target);
0975: }
0976:
0977: public void setForeignKey(ForeignKey fk) {
0978: _val.setForeignKey(fk);
0979: }
0980:
0981: public int getJoinDirection() {
0982: return _val.getJoinDirection();
0983: }
0984:
0985: public void setJoinDirection(int direction) {
0986: _val.setJoinDirection(direction);
0987: }
0988:
0989: public void setForeignKey(Row row, OpenJPAStateManager sm)
0990: throws SQLException {
0991: _val.setForeignKey(row, sm);
0992: }
0993:
0994: public void whereForeignKey(Row row, OpenJPAStateManager sm)
0995: throws SQLException {
0996: _val.whereForeignKey(row, sm);
0997: }
0998:
0999: public ClassMapping[] getIndependentTypeMappings() {
1000: return _val.getIndependentTypeMappings();
1001: }
1002:
1003: public int getSelectSubclasses() {
1004: return _val.getSelectSubclasses();
1005: }
1006:
1007: public Unique getValueUnique() {
1008: return _val.getValueUnique();
1009: }
1010:
1011: public void setValueUnique(Unique unq) {
1012: _val.setValueUnique(unq);
1013: }
1014:
1015: public Index getValueIndex() {
1016: return _val.getValueIndex();
1017: }
1018:
1019: public void setValueIndex(Index idx) {
1020: _val.setValueIndex(idx);
1021: }
1022:
1023: public boolean getUseClassCriteria() {
1024: return _val.getUseClassCriteria();
1025: }
1026:
1027: public void setUseClassCriteria(boolean criteria) {
1028: _val.setUseClassCriteria(criteria);
1029: }
1030:
1031: public int getPolymorphic() {
1032: return _val.getPolymorphic();
1033: }
1034:
1035: public void setPolymorphic(int poly) {
1036: _val.setPolymorphic(poly);
1037: }
1038:
1039: public void mapConstraints(String name, boolean adapt) {
1040: _val.mapConstraints(name, adapt);
1041: }
1042:
1043: public void copyMappingInfo(ValueMapping vm) {
1044: _val.copyMappingInfo(vm);
1045: }
1046: }
|