You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2006/07/19 23:35:07 UTC

svn commit: r423615 [11/44] - in /incubator/openjpa/trunk: ./ openjpa-jdbc-5/ openjpa-jdbc-5/src/ openjpa-jdbc-5/src/main/ openjpa-jdbc-5/src/main/java/ openjpa-jdbc-5/src/main/java/org/ openjpa-jdbc-5/src/main/java/org/apache/ openjpa-jdbc-5/src/main/...

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Discriminator.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Discriminator.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Discriminator.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Discriminator.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.Schemas;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.RowManager;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.MetaDataContext;
+import org.apache.openjpa.meta.MetaDataModes;
+import org.apache.openjpa.meta.MetaDataRepository;
+import org.apache.openjpa.util.InternalException;
+
+/**
+ * Handles determining the object class of database records.
+ *
+ * @author Abe White
+ */
+public class Discriminator
+    implements DiscriminatorStrategy, MetaDataContext, MetaDataModes {
+
+    /**
+     * Null discriminator value marker.
+     */
+    public static final Object NULL = new Object();
+
+    private static final Localizer _loc = Localizer.forPackage
+        (Discriminator.class);
+
+    private final ClassMapping _mapping;
+    private final DiscriminatorMappingInfo _info;
+    private DiscriminatorStrategy _strategy = null;
+    private int _resMode = MODE_NONE;
+
+    private Column[] _cols = Schemas.EMPTY_COLUMNS;
+    private ColumnIO _io = null;
+    private Index _idx = null;
+    private boolean _subsLoaded = false;
+    private Object _value = null;
+
+    /**
+     * Constructor. Supply owning mapping.
+     */
+    public Discriminator(ClassMapping mapping) {
+        _mapping = mapping;
+        _info = getMappingRepository().newMappingInfo(this);
+    }
+
+    public MetaDataRepository getRepository() {
+        return _mapping.getRepository();
+    }
+
+    public MappingRepository getMappingRepository() {
+        return _mapping.getMappingRepository();
+    }
+
+    /**
+     * Return the owning mapping.
+     */
+    public ClassMapping getClassMapping() {
+        return _mapping;
+    }
+
+    /**
+     * The strategy used for class discrimination.
+     */
+    public DiscriminatorStrategy getStrategy() {
+        return _strategy;
+    }
+
+    /**
+     * The strategy used for class discrimination. The <code>adapt</code>
+     * parameter determines whether to adapt when mapping the strategy;
+     * use null if the strategy should not be mapped.
+     */
+    public void setStrategy(DiscriminatorStrategy strategy, Boolean adapt) {
+        // set strategy first so we can access it during mapping
+        DiscriminatorStrategy orig = _strategy;
+        _strategy = strategy;
+        if (strategy != null) {
+            try {
+                strategy.setDiscriminator(this);
+                if (adapt != null)
+                    strategy.map(adapt.booleanValue());
+            } catch (RuntimeException re) {
+                // reset strategy
+                _strategy = orig;
+                throw re;
+            }
+        }
+    }
+
+    /**
+     * The discriminator value.
+     */
+    public Object getValue() {
+        return _value;
+    }
+
+    /**
+     * The discriminator value.
+     */
+    public void setValue(Object value) {
+        _value = value;
+    }
+
+    /**
+     * Raw mapping data.
+     */
+    public DiscriminatorMappingInfo getMappingInfo() {
+        return _info;
+    }
+
+    /**
+     * Columns used by this Discriminator.
+     */
+    public Column[] getColumns() {
+        return _cols;
+    }
+
+    /**
+     * Columns used by this Discriminator.
+     */
+    public void setColumns(Column[] cols) {
+        if (cols == null)
+            cols = Schemas.EMPTY_COLUMNS;
+        _cols = cols;
+    }
+
+    /**
+     * I/O information on the discriminator columns.
+     */
+    public ColumnIO getColumnIO() {
+        return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
+    }
+
+    /**
+     * I/O information on the discriminator columns.
+     */
+    public void setColumnIO(ColumnIO io) {
+        _io = io;
+    }
+
+    /**
+     * Index on the Discriminator columns, or null if none.
+     */
+    public Index getIndex() {
+        return _idx;
+    }
+
+    /**
+     * Index on the Discriminator columns, or null if none.
+     */
+    public void setIndex(Index idx) {
+        _idx = idx;
+    }
+
+    /**
+     * Increment the reference count of used schema components.
+     */
+    public void refSchemaComponents() {
+        for (int i = 0; i < _cols.length; i++)
+            _cols[i].ref();
+    }
+
+    /**
+     * Clear mapping information, including strategy.
+     */
+    public void clearMapping() {
+        _strategy = null;
+        _cols = Schemas.EMPTY_COLUMNS;
+        _idx = null;
+        _value = null;
+        _info.clear();
+        setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
+    }
+
+    /**
+     * Update {@link MappingInfo} with our current mapping information.
+     */
+    public void syncMappingInfo() {
+        _info.syncWith(this);
+    }
+
+    /**
+     * Resolve mode.
+     */
+    public int getResolve() {
+        return _resMode;
+    }
+
+    /**
+     * Resolve mode.
+     */
+    public void setResolve(int mode) {
+        _resMode = mode;
+    }
+
+    /**
+     * Resolve mode.
+     */
+    public void setResolve(int mode, boolean on) {
+        if (mode == MODE_NONE)
+            _resMode = mode;
+        else if (on)
+            _resMode |= mode;
+        else
+            _resMode &= ~mode;
+    }
+
+    /**
+     * Resolve mapping information.
+     */
+    public boolean resolve(int mode) {
+        if ((_resMode & mode) == mode)
+            return true;
+        int cur = _resMode;
+        _resMode |= mode;
+        if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
+            resolveMapping();
+        if ((mode & MODE_MAPPING_INIT) != 0 && (cur & MODE_MAPPING_INIT) == 0)
+            _strategy.initialize();
+        return false;
+    }
+
+    /**
+     * Setup mapping.
+     */
+    private void resolveMapping() {
+        // map strategy
+        MappingRepository repos = getMappingRepository();
+        if (_strategy == null)
+            repos.getStrategyInstaller().installStrategy(this);
+        Log log = repos.getLog();
+        if (log.isTraceEnabled())
+            log.trace(_loc.get("strategy", this, _strategy.getAlias()));
+
+        // mark columns as mapped
+        Column[] cols = getColumns();
+        ColumnIO io = getColumnIO();
+        for (int i = 0; i < cols.length; i++) {
+            if (io.isInsertable(i, false))
+                cols[i].setFlag(Column.FLAG_DIRECT_INSERT, true);
+            if (io.isUpdatable(i, false))
+                cols[i].setFlag(Column.FLAG_DIRECT_UPDATE, true);
+        }
+    }
+
+    /**
+     * Whether this Discriminator has loaded subclasses yet.
+     */
+    public boolean getSubclassesLoaded() {
+        if (!_subsLoaded) {
+            ClassMapping sup = _mapping.getPCSuperclassMapping();
+            if (sup != null && sup.getDiscriminator().getSubclassesLoaded())
+                _subsLoaded = true;
+        }
+        return _subsLoaded;
+    }
+
+    /**
+     * Whether this Discriminator has loaded subclasses yet.
+     */
+    public void setSubclassesLoaded(boolean loaded) {
+        _subsLoaded = loaded;
+    }
+
+    ////////////////////////////////////////
+    // DiscriminatorStrategy implementation
+    ////////////////////////////////////////
+
+    public String getAlias() {
+        return assertStrategy().getAlias();
+    }
+
+    public void map(boolean adapt) {
+        assertStrategy().map(adapt);
+    }
+
+    public void initialize() {
+        assertStrategy().initialize();
+    }
+
+    public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().insert(sm, store, rm);
+    }
+
+    public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().update(sm, store, rm);
+    }
+
+    public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().delete(sm, store, rm);
+    }
+
+    public Boolean isCustomInsert(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomInsert(sm, store);
+    }
+
+    public Boolean isCustomUpdate(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomUpdate(sm, store);
+    }
+
+    public Boolean isCustomDelete(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomDelete(sm, store);
+    }
+
+    public void customInsert(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customInsert(sm, store);
+    }
+
+    public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customUpdate(sm, store);
+    }
+
+    public void customDelete(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customDelete(sm, store);
+    }
+
+    public void setDiscriminator(Discriminator owner) {
+        assertStrategy().setDiscriminator(owner);
+    }
+
+    public boolean select(Select sel, ClassMapping mapping) {
+        return assertStrategy().select(sel, mapping);
+    }
+
+    public void loadSubclasses(JDBCStore store)
+        throws SQLException, ClassNotFoundException {
+        assertStrategy().loadSubclasses(store);
+    }
+
+    public Class getClass(JDBCStore store, ClassMapping base, Result result)
+        throws SQLException, ClassNotFoundException {
+        return assertStrategy().getClass(store, base, result);
+    }
+
+    public SQLBuffer getClassConditions(JDBCStore store, Select sel,
+        Joins joins, ClassMapping base, boolean subs) {
+        return assertStrategy().getClassConditions(store, sel, joins,
+            base, subs);
+    }
+
+    private DiscriminatorStrategy assertStrategy() {
+        if (_strategy == null)
+            throw new InternalException();
+        return _strategy;
+    }
+
+    public String toString() {
+        return _mapping + "<discriminator>";
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Discriminator.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorMappingInfo.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorMappingInfo.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorMappingInfo.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorMappingInfo.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.openjpa.jdbc.meta.strats.NoneDiscriminatorStrategy;
+import org.apache.openjpa.jdbc.meta.strats.SuperclassDiscriminatorStrategy;
+import org.apache.openjpa.jdbc.meta.strats.ValueMapDiscriminatorStrategy;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.SchemaGroup;
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * Information about the mapping from a discriminator to the schema, in
+ * raw form. The columns and tables used in mapping info will not be part of
+ * the {@link SchemaGroup} used at runtime. Rather, they will be structs
+ * with the relevant pieces of information filled in.
+ *
+ * @author Abe White
+ */
+public class DiscriminatorMappingInfo
+    extends MappingInfo {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (DiscriminatorMappingInfo.class);
+
+    private String _value = null;
+
+    /**
+     * Raw discriminator value string.
+     */
+    public String getValue() {
+        return _value;
+    }
+
+    /**
+     * Raw discriminator value string.
+     */
+    public void setValue(String value) {
+        _value = value;
+    }
+
+    /**
+     * Return the discriminator value as an object of the right type.
+     */
+    public Object getValue(Discriminator discrim, boolean adapt) {
+        if (discrim.getValue() != null)
+            return discrim.getValue();
+        if (_value == null)
+            return discrim.getMappingRepository().getMappingDefaults().
+                getDiscriminatorValue(discrim, adapt);
+
+        if (_value.length() > 0 &&
+            (_value.charAt(0) == '-' || Character.isDigit(_value.charAt(0)))) {
+            try {
+                if (_value.indexOf('.') == -1)
+                    return new Integer(_value);
+                return new Double(_value);
+            } catch (RuntimeException re) {
+                throw new MetaDataException(_loc.get("bad-discrim-value",
+                    discrim.getClassMapping(), _value));
+            }
+        }
+        if ("null".equalsIgnoreCase(_value))
+            return (Discriminator.NULL);
+
+        // strip quotes
+        if (_value.length() > 0 && _value.charAt(0) == '\'')
+            return _value.substring(1, _value.length() - 1);
+        return _value;
+    }
+
+    /**
+     * Return the columns set for this discriminator, based on the given
+     * templates.
+     */
+    public Column[] getColumns(Discriminator discrim, Column[] tmplates,
+        boolean adapt) {
+        Table table = discrim.getClassMapping().getTable();
+        discrim.getMappingRepository().getMappingDefaults().populateColumns
+            (discrim, table, tmplates);
+        return createColumns(discrim, null, tmplates, table, adapt);
+    }
+
+    /**
+     * Return the index to set on the discriminator columns, or null if none.
+     */
+    public Index getIndex(Discriminator discrim, Column[] cols, boolean adapt) {
+        Index idx = null;
+        if (cols.length > 0)
+            idx = discrim.getMappingRepository().getMappingDefaults().
+                getIndex(discrim, cols[0].getTable(), cols);
+        return createIndex(discrim, null, idx, cols, adapt);
+    }
+
+    /**
+     * Synchronize internal information with the mapping data for the given
+     * discriminator.
+     */
+    public void syncWith(Discriminator disc) {
+        clear(false);
+
+        // set io before syncing cols
+        setColumnIO(disc.getColumnIO());
+        syncColumns(disc, disc.getColumns(), disc.getValue() != null
+            && !(disc.getValue()instanceof String));
+        syncIndex(disc, disc.getIndex());
+        if (disc.getValue() == Discriminator.NULL)
+            _value = "null";
+        else if (disc.getValue() != null)
+            _value = disc.getValue().toString();
+
+        if (disc.getStrategy() == null
+            || disc.getStrategy()instanceof SuperclassDiscriminatorStrategy)
+            return;
+
+        // explicit discriminator strategy if:
+        // - unmapped class and discriminator is mapped
+        // - final base class and discriminator is mapped
+        // - table-per-class subclass and discriminator is mapped
+        // - mapped subclass and doesn't rely on superclass discriminator
+        // - mapped base class and doesn't use value-map strategy with value
+        //   and isn't a final class that uses the final strategy
+        ClassMapping cls = disc.getClassMapping();
+        String strat = disc.getStrategy().getAlias();
+        boolean sync = false;
+
+        if (!cls.isMapped()
+            || (cls.getJoinablePCSuperclassMapping() != null
+            && Modifier.isFinal(cls.getDescribedType().getModifiers()))
+            || (cls.getJoinablePCSuperclassMapping() == null
+            && cls.getMappedPCSuperclassMapping() != null))
+            sync = !NoneDiscriminatorStrategy.ALIAS.equals(strat);
+        else
+            sync = cls.getJoinablePCSuperclassMapping() != null
+                || _value == null
+                || !ValueMapDiscriminatorStrategy.ALIAS.equals(strat);
+
+        if (sync)
+            setStrategy(strat);
+    }
+
+    protected void clear(boolean canFlags) {
+        super.clear(canFlags);
+        _value = null;
+    }
+
+    public void copy(MappingInfo info) {
+        super.copy(info);
+        if (!(info instanceof DiscriminatorMappingInfo))
+            return;
+
+        if (_value == null)
+            _value = ((DiscriminatorMappingInfo) info).getValue();
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorMappingInfo.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorStrategy.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorStrategy.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorStrategy.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+
+/**
+ * Handles determining the object class of database records.
+ *
+ * @author Abe White
+ */
+public interface DiscriminatorStrategy
+    extends Strategy {
+
+    /**
+     * Set the Discriminator that uses this strategy. This will be called
+     * before use.
+     */
+    public void setDiscriminator(Discriminator owner);
+
+    /**
+     * Select the data for this Discriminator.
+     *
+     * @param mapping the known base class being selected; this may
+     * not be the base class in the inheritance hierarchy
+     * @return true if anything was selected; false otherwise
+     */
+    public boolean select(Select sel, ClassMapping mapping);
+
+    /**
+     * Load all subclasses of the owning class mapping into the JVM.
+     */
+    public void loadSubclasses(JDBCStore store)
+        throws SQLException, ClassNotFoundException;
+
+    /**
+     * Return the class for the current result row.
+     */
+    public Class getClass(JDBCStore store, ClassMapping base, Result result)
+        throws SQLException, ClassNotFoundException;
+
+    /**
+     * Return SQL to limit the classes selected as much as possible to the
+     * given base class, and optionally its subclasses. Return null if
+     * no conditions needed. The select and joins instances are supplied
+     * in order to get column aliases.
+     */
+    public SQLBuffer getClassConditions(JDBCStore store, Select sel,
+        Joins joins, ClassMapping base, boolean subs);
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DiscriminatorStrategy.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Embeddable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Embeddable.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Embeddable.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Embeddable.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+/**
+ * Interface for field strategies that can managed fields of
+ * embedded-element, embedded-key, and embedded-value objects. Fields of
+ * directly embedded objects do not have to implement this interface.
+ *
+ * @author Abe White
+ * @since 4.0
+ */
+public interface Embeddable {
+
+    public static final Object UNSUPPORTED = new Object();
+
+    /**
+     * Return the columns used by this strategy.
+     */
+    public Column[] getColumns();
+
+    /**
+     * Return column I/O information for this mapping.
+     */
+    public ColumnIO getColumnIO();
+
+    /**
+     * Return the arguments needed to extract datastore values via
+     * {@link Result#getObject} for each column.
+     */
+    public Object[] getResultArguments();
+
+    /**
+     * Convert the given Java value to its datastore equivalent. If this
+     * mapping occupies multiple columns, return an object array with one
+     * element per column. For relation id columns, return the state manager
+     * the column depends on.
+     */
+    public Object toEmbeddedDataStoreValue(Object val, JDBCStore store);
+
+    /**
+     * Convert the given datastore value to its Java equivalent.
+     * If {@link #getColumns} returns multiple columns, the given datastore
+     * value will be an object array of the corresponding length. This method
+     * must only be supported by mappings of embedded id objects. In other
+     * cases {@link #loadEmbedded} will be used instead. Return
+     * {@link #UNSUPPORTED} if this mapping cannot support this method.
+     */
+    public Object toEmbeddedObjectValue(Object val);
+
+    /**
+     * Load this strategy's field by transforming the given datastore value.
+     * If {@link #getColumns} returns multiple columns, the given datastore
+     * value will be an object array of the corresponding length. The value
+     * does not have to be loaded immediately; it may be stored as impl data.
+     */
+    public void loadEmbedded(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Object val)
+        throws SQLException;
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/Embeddable.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,1013 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.strats.NoneFieldStrategy;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.jdbc.schema.Unique;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.Row;
+import org.apache.openjpa.jdbc.sql.RowManager;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.jdbc.sql.SelectExecutor;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.InternalException;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * Specialization of metadata for relational databases.
+ *
+ * @author Abe White
+ */
+public class FieldMapping
+    extends FieldMetaData
+    implements ValueMapping, FieldStrategy {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (FieldMapping.class);
+
+    private final ValueMapping _val;
+    private final ValueMapping _key;
+    private final ValueMapping _elem;
+    private final FieldMappingInfo _info;
+    private final JDBCColumnOrder _orderCol = new JDBCColumnOrder();
+    private FieldStrategy _strategy = null;
+
+    private ForeignKey _fk = null;
+    private ColumnIO _io = null;
+    private Unique _unq = null;
+    private Index _idx = null;
+    private boolean _outer = false;
+    private int _fetchMode = Integer.MAX_VALUE;
+
+    /**
+     * Constructor.
+     */
+    public FieldMapping(String name, Class type, ClassMapping owner) {
+        super(name, type, owner);
+        _info = owner.getMappingRepository().newMappingInfo(this);
+        _val = (ValueMapping) getValue();
+        _key = (ValueMapping) getKey();
+        _elem = (ValueMapping) getElement();
+
+        setUsesIntermediate(false);
+        setUsesImplData(Boolean.FALSE);
+    }
+
+    ///////
+    // ORM
+    ///////
+
+    /**
+     * Raw mapping data about field's join to parent table, as well as
+     * miscellaneous specialized columns like order column.
+     */
+    public FieldMappingInfo getMappingInfo() {
+        return _info;
+    }
+
+    /**
+     * The strategy used to map this mapping.
+     */
+    public FieldStrategy getStrategy() {
+        return _strategy;
+    }
+
+    /**
+     * The strategy used to map this mapping. The <code>adapt</code>
+     * parameter determines whether to adapt when mapping the strategy;
+     * use null if the strategy should not be mapped.
+     */
+    public void setStrategy(FieldStrategy strategy, Boolean adapt) {
+        // set strategy first so we can access it during mapping
+        FieldStrategy orig = _strategy;
+        _strategy = strategy;
+        if (strategy != null) {
+            try {
+                strategy.setFieldMapping(this);
+                if (adapt != null)
+                    strategy.map(adapt.booleanValue());
+            } catch (RuntimeException re) {
+                // reset strategy
+                _strategy = orig;
+                throw re;
+            }
+
+            // if set to unmapped, clear defined field cache in parent
+            if (!isMapped())
+                getDefiningMapping().clearDefinedFieldCache();
+        }
+    }
+
+    /**
+     * The mapping's primary table.
+     */
+    public Table getTable() {
+        if (_fk != null)
+            return _fk.getTable();
+        if (_val.getForeignKey() != null)
+            return _val.getForeignKey().getTable();
+        return getDefiningMapping().getTable();
+    }
+
+    /**
+     * I/O information on the join columns.
+     */
+    public ColumnIO getJoinColumnIO() {
+        return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
+    }
+
+    /**
+     * I/O information on the join columns.
+     */
+    public void setJoinColumnIO(ColumnIO io) {
+        _io = io;
+    }
+
+    /**
+     * Foreign key linking the field table to the class' primary table.
+     */
+    public ForeignKey getJoinForeignKey() {
+        return _fk;
+    }
+
+    /**
+     * Foreign key linking the field table to the class' primary table.
+     */
+    public void setJoinForeignKey(ForeignKey fk) {
+        _fk = fk;
+    }
+
+    /**
+     * Unique constraint on join foreign key columns.
+     */
+    public Unique getJoinUnique() {
+        return _unq;
+    }
+
+    /**
+     * Unique constraint on join foreign key columns.
+     */
+    public void setJoinUnique(Unique unq) {
+        _unq = unq;
+    }
+
+    /**
+     * Index on join foreign key columns.
+     */
+    public Index getJoinIndex() {
+        return _idx;
+    }
+
+    /**
+     * Index on join foreign key columns.
+     */
+    public void setJoinIndex(Index idx) {
+        _idx = idx;
+    }
+
+    /**
+     * Whether to use an outer join from the class' primary table.
+     */
+    public boolean isJoinOuter() {
+        return _outer;
+    }
+
+    /**
+     * Whether to use an outer join from the class' primary table.
+     */
+    public void setJoinOuter(boolean outer) {
+        _outer = outer;
+    }
+
+    /**
+     * Field order column, if any.
+     */
+    public Column getOrderColumn() {
+        return _orderCol.getColumn();
+    }
+
+    /**
+     * Field order column, if any.
+     */
+    public void setOrderColumn(Column order) {
+        _orderCol.setColumn(order);
+    }
+
+    /**
+     * I/O information for order column.
+     */
+    public ColumnIO getOrderColumnIO() {
+        return _orderCol.getColumnIO();
+    }
+
+    /**
+     * I/O information for order column.
+     */
+    public void setOrderColumnIO(ColumnIO io) {
+        _orderCol.setColumnIO(io);
+    }
+
+    /**
+     * Increment the reference count of used schema components.
+     */
+    public void refSchemaComponents() {
+        if (_fk != null) {
+            _fk.ref();
+            _fk.refColumns();
+        }
+        if (_orderCol.getColumn() != null)
+            _orderCol.getColumn().ref();
+        _val.refSchemaComponents();
+        _key.refSchemaComponents();
+        _elem.refSchemaComponents();
+    }
+
+    /**
+     * Clear mapping information, including strategy.
+     */
+    public void clearMapping() {
+        _strategy = null;
+        _fk = null;
+        _unq = null;
+        _idx = null;
+        _outer = false;
+        _orderCol.setColumn(null);
+        _val.clearMapping();
+        _key.clearMapping();
+        _elem.clearMapping();
+        _info.clear();
+        setResolve(MODE_MAPPING, false);
+    }
+
+    /**
+     * Update {@link MappingInfo} with our current mapping information.
+     */
+    public void syncMappingInfo() {
+        if (isVersion()) {
+            // we rely on the fact that the version will setup our mapping
+            // info correctly when it is synced
+        } else if (getMappedByMapping() != null) {
+            _info.clear();
+            _val.getValueInfo().clear();
+            _key.getValueInfo().clear();
+            _elem.getValueInfo().clear();
+
+            FieldMapping mapped = getMappedByMapping();
+            _info.syncStrategy(this);
+            if (_orderCol.getColumn() != null
+                && mapped.getOrderColumn() == null)
+                _info.syncOrderColumn(this);
+            _val.getValueInfo().setUseClassCriteria
+                (_val.getUseClassCriteria());
+            _key.getValueInfo().setUseClassCriteria
+                (_key.getUseClassCriteria());
+            _elem.getValueInfo().setUseClassCriteria
+                (_elem.getUseClassCriteria());
+        } else {
+            _info.syncWith(this);
+            _val.syncMappingInfo();
+            _key.syncMappingInfo();
+            _elem.syncMappingInfo();
+        }
+    }
+
+    /**
+     * Returns true if field class does not use the "none" strategy (including
+     * if it has a null strategy, and therefore is probably in the process of
+     * being mapped).
+     */
+    public boolean isMapped() {
+        return _strategy != NoneFieldStrategy.getInstance();
+    }
+
+    //////////////////////
+    // MetaData interface
+    //////////////////////
+
+    /**
+     * The eager fetch mode, as one of the eager constants in
+     * {@link JDBCFetchConfiguration}.
+     */
+    public int getEagerFetchMode() {
+        if (_fetchMode == Integer.MAX_VALUE)
+            _fetchMode = FetchConfiguration.DEFAULT;
+        return _fetchMode;
+    }
+
+    /**
+     * The eager fetch mode, as one of the eager constants in
+     * {@link JDBCFetchConfiguration}.
+     */
+    public void setEagerFetchMode(int mode) {
+        _fetchMode = mode;
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link FieldMetaData#getRepository}
+     */
+    public MappingRepository getMappingRepository() {
+        return (MappingRepository) getRepository();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link FieldMetaData#getDefiningMetaData}
+     */
+    public ClassMapping getDefiningMapping() {
+        return (ClassMapping) getDefiningMetaData();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link FieldMetaData#getDeclaringMetaData}
+     */
+    public ClassMapping getDeclaringMapping() {
+        return (ClassMapping) getDeclaringMetaData();
+    }
+
+    /**
+     * Convenience method to perform cast from {@link FieldMetaData#getKey}
+     */
+    public ValueMapping getKeyMapping() {
+        return _key;
+    }
+
+    /**
+     * Convenience method to perform cast from {@link FieldMetaData#getElement}
+     */
+    public ValueMapping getElementMapping() {
+        return _elem;
+    }
+
+    /**
+     * Convenience method to perform cast from {@link FieldMetaData#getValue}
+     */
+    public ValueMapping getValueMapping() {
+        return (ValueMapping) getValue();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link FieldMetaData#getMappedByMetaData}
+     */
+    public FieldMapping getMappedByMapping() {
+        return (FieldMapping) getMappedByMetaData();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link FieldMetaData#getInverseMetaDatas}
+     */
+    public FieldMapping[] getInverseMappings() {
+        return (FieldMapping[]) getInverseMetaDatas();
+    }
+
+    public boolean resolve(int mode) {
+        int cur = getResolve();
+        if (super.resolve(mode))
+            return true;
+        if ((mode & MODE_MAPPING) != 0 && (cur & MODE_MAPPING) == 0)
+            resolveMapping();
+        if ((mode & MODE_MAPPING_INIT) != 0 && (cur & MODE_MAPPING_INIT) == 0)
+            initializeMapping();
+        return false;
+    }
+
+    /**
+     * Resolve the mapping information for this field.
+     */
+    private void resolveMapping() {
+        MappingRepository repos = getMappingRepository();
+        if (repos.getMappingDefaults().defaultMissingInfo()) {
+            // copy embedded template mapping info
+            ClassMapping cls = getDefiningMapping();
+            if (cls.getEmbeddingMapping() != null) {
+                ClassMapping orig = repos.getMapping(cls.getDescribedType(),
+                    cls.getEnvClassLoader(), true);
+                FieldMapping tmplate = orig.getFieldMapping(getName());
+                if (tmplate != null)
+                    copyMappingInfo(tmplate);
+            }
+            // copy superclass field info
+            else if (cls.isMapped() && cls.getPCSuperclass() != null
+                && cls.getDescribedType() != getDeclaringType()) {
+                FieldMapping sup = cls.getPCSuperclassMapping().
+                    getFieldMapping(getName());
+                if (sup != null)
+                    copyMappingInfo(sup);
+            }
+        }
+
+        if (_strategy == null) {
+            if (isVersion())
+                _strategy = NoneFieldStrategy.getInstance();
+            else
+                repos.getStrategyInstaller().installStrategy(this);
+        }
+        Log log = getRepository().getLog();
+        if (log.isTraceEnabled())
+            log.trace(_loc.get("field-strategy", getName(),
+                _strategy.getAlias()));
+
+        // mark mapped columns
+        if (_orderCol.getColumn() != null) {
+            if (getOrderColumnIO().isInsertable(0, false))
+                _orderCol.getColumn().setFlag(Column.FLAG_DIRECT_INSERT, true);
+            if (getOrderColumnIO().isUpdatable(0, false))
+                _orderCol.getColumn().setFlag(Column.FLAG_DIRECT_UPDATE, true);
+        }
+        if (_fk != null) {
+            Column[] cols = _fk.getColumns();
+            ColumnIO io = getJoinColumnIO();
+            for (int i = 0; i < cols.length; i++) {
+                if (io.isInsertable(i, false))
+                    cols[i].setFlag(Column.FLAG_FK_INSERT, true);
+                if (io.isUpdatable(i, false))
+                    cols[i].setFlag(Column.FLAG_FK_UPDATE, true);
+            }
+        }
+
+        _val.resolve(MODE_MAPPING);
+        _key.resolve(MODE_MAPPING);
+        _elem.resolve(MODE_MAPPING);
+    }
+
+    /**
+     * Copy mapping info from the given instance to this one.
+     */
+    public void copyMappingInfo(FieldMapping fm) {
+        setMappedBy(fm.getMappedBy());
+        _info.copy(fm.getMappingInfo());
+        _val.copyMappingInfo(fm.getValueMapping());
+        _key.copyMappingInfo(fm.getKeyMapping());
+        _elem.copyMappingInfo(fm.getElementMapping());
+    }
+
+    /**
+     * Prepare mapping for runtime use.
+     */
+    private void initializeMapping() {
+        _val.resolve(MODE_MAPPING_INIT);
+        _key.resolve(MODE_MAPPING_INIT);
+        _val.resolve(MODE_MAPPING_INIT);
+        _strategy.initialize();
+    }
+
+    public void copy(FieldMetaData fmd) {
+        super.copy(fmd);
+        if (_fetchMode == Integer.MAX_VALUE)
+            _fetchMode = ((FieldMapping) fmd).getEagerFetchMode();
+    }
+
+    protected boolean validateDataStoreExtensionPrefix(String prefix) {
+        return "jdbc-".equals(prefix);
+    }
+
+    ////////////////////////////////
+    // FieldStrategy implementation
+    ////////////////////////////////
+
+    public String getAlias() {
+        return assertStrategy().getAlias();
+    }
+
+    public void map(boolean adapt) {
+        assertStrategy().map(adapt);
+    }
+
+    /**
+     * Map this field to its table, optionally requiring that it be
+     * in another table. Utility method for use by mapping strategies.
+     */
+    public void mapJoin(boolean adapt, boolean joinRequired) {
+        Table table = _info.getTable(this, joinRequired, adapt);
+        ForeignKey join = null;
+        if (table != null)
+            join = _info.getJoin(this, table, adapt);
+        if (join == null && joinRequired)
+            throw new MetaDataException(_loc.get("join-required", this));
+
+        if (join == null) {
+            _info.assertNoJoin(this, true);
+            _info.assertNoForeignKey(this, !adapt);
+            _info.assertNoUnique(this, !adapt);
+            _info.assertNoIndex(this, !adapt);
+        } else {
+            _fk = join;
+            _io = _info.getColumnIO();
+            _outer = _info.isJoinOuter();
+            _unq = _info.getJoinUnique(this, false, adapt);
+            _idx = _info.getJoinIndex(this, adapt);
+        }
+    }
+
+    /**
+     * Maps the primary key on the secondary table for this field, if the
+     * user's defaults create one. This must be called after
+     * this field is mapped so that it's table has its columns set.
+     */
+    public void mapPrimaryKey(boolean adapt) {
+        if (adapt && _fk != null && _fk.getTable().getPrimaryKey() == null)
+            getMappingRepository().getMappingDefaults().
+                installPrimaryKey(this, _fk.getTable());
+    }
+
+    public void initialize() {
+        assertStrategy().initialize();
+    }
+
+    public void insert(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().insert(sm, store, rm);
+    }
+
+    public void update(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().update(sm, store, rm);
+    }
+
+    public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
+        throws SQLException {
+        assertStrategy().delete(sm, store, rm);
+    }
+
+    /**
+     * Delete the row for this object if the reference foreign key exists.
+     * Utility method for use by mapping strategies.
+     */
+    public void deleteRow(OpenJPAStateManager sm, JDBCStore store,
+        RowManager rm)
+        throws SQLException {
+        if (_fk != null) {
+            Row row = rm.getRow(getTable(), Row.ACTION_DELETE, sm, true);
+            row.whereForeignKey(_fk, sm);
+        }
+    }
+
+    /**
+     * Return the row to use for this field. This method is meant only for
+     * single-value fields that might reside in a table that is joined to
+     * the primary table through the join foreign key. It is not
+     * meant for multi-valued fields like collections and maps. The method
+     * checks whether we're using an outer join and if so it deletes the
+     * field's previous value, then if the field is non-null returns an insert
+     * row for the new value. The join foreign key will already be set on
+     * the returned row; mapping strategies just need to set their own values.
+     * Utility method for use by mapping strategies.
+     */
+    public Row getRow(OpenJPAStateManager sm, JDBCStore store, RowManager rm,
+        int action)
+        throws SQLException {
+        Row row = null;
+        boolean newOuterRow = false;
+        if (_fk != null && _outer && action != Row.ACTION_DELETE) {
+            // if updating with outer join, delete old value first, then insert;
+            // we can't just update b/c the row might not exist
+            if (action == Row.ACTION_UPDATE) {
+                // maybe some other field already is updating?
+                row = rm.getRow(getTable(), Row.ACTION_UPDATE, sm, false);
+                if (row == null) {
+                    Row del = rm.getRow(getTable(), Row.ACTION_DELETE, sm,
+                        true);
+                    del.whereForeignKey(_fk, sm);
+                }
+            } else
+                row = rm.getRow(getTable(), Row.ACTION_INSERT, sm, false);
+
+            // only update/insert if the row exists already or the value is
+            // not null/default
+            if (row == null && !isNullValue(sm)) {
+                row = rm.getRow(getTable(), Row.ACTION_INSERT, sm, true);
+                newOuterRow = true;
+            }
+        } else
+            row = rm.getRow(getTable(), action, sm, true);
+
+        // setup fk
+        if (row != null && _fk != null) {
+            if (row.getAction() == Row.ACTION_INSERT)
+                row.setForeignKey(_fk, _io, sm);
+            else
+                row.whereForeignKey(_fk, sm);
+
+            // if this is a new outer joined row, mark it invalid until
+            // some mapping actually sets information on it
+            if (newOuterRow)
+                row.setValid(false);
+        }
+        return row;
+    }
+
+    /**
+     * Return true if this field is null/default in the given instance.
+     */
+    private boolean isNullValue(OpenJPAStateManager sm) {
+        switch (getTypeCode()) {
+            case JavaTypes.BOOLEAN:
+                return !sm.fetchBoolean(getIndex());
+            case JavaTypes.BYTE:
+                return sm.fetchByte(getIndex()) == 0;
+            case JavaTypes.CHAR:
+                return sm.fetchChar(getIndex()) == 0;
+            case JavaTypes.DOUBLE:
+                return sm.fetchDouble(getIndex()) == 0;
+            case JavaTypes.FLOAT:
+                return sm.fetchFloat(getIndex()) == 0;
+            case JavaTypes.INT:
+                return sm.fetchInt(getIndex()) == 0;
+            case JavaTypes.LONG:
+                return sm.fetchLong(getIndex()) == 0;
+            case JavaTypes.SHORT:
+                return sm.fetchShort(getIndex()) == 0;
+            case JavaTypes.STRING:
+                return sm.fetchString(getIndex()) == null;
+            default:
+                return sm.fetchObject(getIndex()) == null;
+        }
+    }
+
+    public Boolean isCustomInsert(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomInsert(sm, store);
+    }
+
+    public Boolean isCustomUpdate(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomUpdate(sm, store);
+    }
+
+    public Boolean isCustomDelete(OpenJPAStateManager sm, JDBCStore store) {
+        return assertStrategy().isCustomDelete(sm, store);
+    }
+
+    public void customInsert(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customInsert(sm, store);
+    }
+
+    public void customUpdate(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customUpdate(sm, store);
+    }
+
+    public void customDelete(OpenJPAStateManager sm, JDBCStore store)
+        throws SQLException {
+        assertStrategy().customDelete(sm, store);
+    }
+
+    public void setFieldMapping(FieldMapping owner) {
+        assertStrategy().setFieldMapping(owner);
+    }
+
+    public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchConfiguration fetch) {
+        return assertStrategy().supportsSelect(sel, type, sm, store, fetch);
+    }
+
+    public void selectEagerParallel(SelectExecutor sel, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchState fetchState, int eagerMode) {
+        assertStrategy().selectEagerParallel(sel, sm, store, fetchState,
+            eagerMode);
+    }
+
+    public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchState fetchState, int eagerMode) {
+        assertStrategy().selectEagerJoin(sel, sm, store, fetchState,
+            eagerMode);
+    }
+
+    public boolean isEagerSelectToMany() {
+        return assertStrategy().isEagerSelectToMany();
+    }
+
+    public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, int eagerMode) {
+        return assertStrategy().select(sel, sm, store, fetchState, eagerMode);
+    }
+
+    /**
+     * Return any joins needed to get from the primary table to this table.
+     */
+    public Joins join(Select sel) {
+        if (_fk == null)
+            return null;
+
+        Joins joins = sel.newJoins();
+        if (_outer)
+            return joins.outerJoin(_fk, true, false);
+        return joins.join(_fk, true, false);
+    }
+
+    /**
+     * Add a <code>wherePrimaryKey</code> or <code>whereForeignKey</code>
+     * condition to the given select, depending on whether we have a join
+     * foreign key.
+     */
+    public void wherePrimaryKey(Select sel, OpenJPAStateManager sm,
+        JDBCStore store) {
+        if (_fk != null)
+            sel.whereForeignKey(_fk, sm.getObjectId(), getDefiningMapping(),
+                store);
+        else
+            sel.wherePrimaryKey(sm.getObjectId(), getDefiningMapping(),
+                store);
+    }
+
+    /**
+     * Add ordering to the given select for all non-relation order values,
+     * including the synthetic order column, if any.
+     *
+     * @param elem the related type we're fetching, or null
+     * @param joins the joins to this field's table
+     */
+    public void orderLocal(Select sel, ClassMapping elem, Joins joins) {
+        _orderCol.order(sel, elem, joins);
+        JDBCOrder[] orders = (JDBCOrder[]) getOrders();
+        for (int i = 0; i < orders.length; i++)
+            if (!orders[i].isInRelation())
+                orders[i].order(sel, elem, joins);
+    }
+
+    /**
+     * Add ordering to the given select for all relation-based values.
+     *
+     * @param elem the related type we're fetching
+     * @param joins the joins across the relation
+     */
+    public void orderRelation(Select sel, ClassMapping elem, Joins joins) {
+        JDBCOrder[] orders = (JDBCOrder[]) getOrders();
+        for (int i = 0; i < orders.length; i++)
+            if (orders[i].isInRelation())
+                orders[i].order(sel, elem, joins);
+    }
+
+    public Object loadEagerParallel(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Object res)
+        throws SQLException {
+        return assertStrategy().loadEagerParallel(sm, store, fetchState, res);
+    }
+
+    public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Result res)
+        throws SQLException {
+        assertStrategy().loadEagerJoin(sm, store, fetchState, res);
+    }
+
+    public void load(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Result res)
+        throws SQLException {
+        assertStrategy().load(sm, store, fetchState, res);
+    }
+
+    public void load(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException {
+        assertStrategy().load(sm, store, fetchState);
+    }
+
+    public Object toDataStoreValue(Object val, JDBCStore store) {
+        return assertStrategy().toDataStoreValue(val, store);
+    }
+
+    public Object toKeyDataStoreValue(Object val, JDBCStore store) {
+        return assertStrategy().toKeyDataStoreValue(val, store);
+    }
+
+    public void appendIsEmpty(SQLBuffer sql, Select sel, Joins joins) {
+        assertStrategy().appendIsEmpty(sql, sel, joins);
+    }
+
+    public void appendIsNotEmpty(SQLBuffer sql, Select sel, Joins joins) {
+        assertStrategy().appendIsNotEmpty(sql, sel, joins);
+    }
+
+    public void appendIsNull(SQLBuffer sql, Select sel, Joins joins) {
+        assertStrategy().appendIsNull(sql, sel, joins);
+    }
+
+    public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins) {
+        assertStrategy().appendIsNotNull(sql, sel, joins);
+    }
+
+    public void appendSize(SQLBuffer sql, Select sel, Joins joins) {
+        assertStrategy().appendSize(sql, sel, joins);
+    }
+
+    public Joins join(Joins joins, boolean forceOuter) {
+        return assertStrategy().join(joins, forceOuter);
+    }
+
+    public Joins joinKey(Joins joins, boolean forceOuter) {
+        return assertStrategy().joinKey(joins, forceOuter);
+    }
+
+    public Joins joinRelation(Joins joins, boolean forceOuter,
+        boolean traverse) {
+        return assertStrategy().joinRelation(joins, forceOuter, traverse);
+    }
+
+    public Joins joinKeyRelation(Joins joins, boolean forceOuter,
+        boolean traverse) {
+        return assertStrategy().joinKeyRelation(joins, forceOuter, traverse);
+    }
+
+    /**
+     * Joins from the owning class' table to the table where this field lies
+     * using the join foreign key. Utility method for use by mapping strategies.
+     */
+    public Joins join(Joins joins, boolean forceOuter, boolean toMany) {
+        if (_fk == null)
+            return joins;
+        if (_outer || forceOuter)
+            return joins.outerJoin(_fk, true, toMany);
+        return joins.join(_fk, true, toMany);
+    }
+
+    public Object loadProjection(JDBCStore store, JDBCFetchState fetchState,
+        Result res, Joins joins)
+        throws SQLException {
+        return assertStrategy().loadProjection(store, fetchState, res, joins);
+    }
+
+    public Object loadKeyProjection(JDBCStore store,
+        JDBCFetchState fetchState, Result res, Joins joins)
+        throws SQLException {
+        return assertStrategy()
+            .loadKeyProjection(store, fetchState, res, joins);
+    }
+
+    public boolean isVersionable() {
+        return assertStrategy().isVersionable();
+    }
+
+    public void where(OpenJPAStateManager sm, JDBCStore store, RowManager rm,
+        Object prevValue)
+        throws SQLException {
+        assertStrategy().where(sm, store, rm, prevValue);
+    }
+
+    private FieldStrategy assertStrategy() {
+        if (_strategy == null)
+            throw new InternalException();
+        return _strategy;
+    }
+
+    ///////////////////////////////
+    // ValueMapping implementation
+    ///////////////////////////////
+
+    public ValueMappingInfo getValueInfo() {
+        return _val.getValueInfo();
+    }
+
+    public ValueHandler getHandler() {
+        return _val.getHandler();
+    }
+
+    public void setHandler(ValueHandler handler) {
+        _val.setHandler(handler);
+    }
+
+    public FieldMapping getFieldMapping() {
+        return this;
+    }
+
+    public ClassMapping getTypeMapping() {
+        return _val.getTypeMapping();
+    }
+
+    public ClassMapping getDeclaredTypeMapping() {
+        return _val.getDeclaredTypeMapping();
+    }
+
+    public ClassMapping getEmbeddedMapping() {
+        return _val.getEmbeddedMapping();
+    }
+
+    public FieldMapping getValueMappedByMapping() {
+        return _val.getValueMappedByMapping();
+    }
+
+    public Column[] getColumns() {
+        return _val.getColumns();
+    }
+
+    public void setColumns(Column[] cols) {
+        _val.setColumns(cols);
+    }
+
+    public ColumnIO getColumnIO() {
+        return _val.getColumnIO();
+    }
+
+    public void setColumnIO(ColumnIO io) {
+        _val.setColumnIO(io);
+    }
+
+    public ForeignKey getForeignKey() {
+        return _val.getForeignKey();
+    }
+
+    public ForeignKey getForeignKey(ClassMapping target) {
+        return _val.getForeignKey(target);
+    }
+
+    public void setForeignKey(ForeignKey fk) {
+        _val.setForeignKey(fk);
+    }
+
+    public int getJoinDirection() {
+        return _val.getJoinDirection();
+    }
+
+    public void setJoinDirection(int direction) {
+        _val.setJoinDirection(direction);
+    }
+
+    public void setForeignKey(Row row, OpenJPAStateManager sm)
+        throws SQLException {
+        _val.setForeignKey(row, sm);
+    }
+
+    public void whereForeignKey(Row row, OpenJPAStateManager sm)
+        throws SQLException {
+        _val.whereForeignKey(row, sm);
+    }
+
+    public ClassMapping[] getIndependentTypeMappings() {
+        return _val.getIndependentTypeMappings();
+    }
+
+    public int getSelectSubclasses() {
+        return _val.getSelectSubclasses();
+    }
+
+    public Unique getValueUnique() {
+        return _val.getValueUnique();
+    }
+
+    public void setValueUnique(Unique unq) {
+        _val.setValueUnique(unq);
+    }
+
+    public Index getValueIndex() {
+        return _val.getValueIndex();
+    }
+
+    public void setValueIndex(Index idx) {
+        _val.setValueIndex(idx);
+    }
+
+    public boolean getUseClassCriteria() {
+        return _val.getUseClassCriteria();
+    }
+
+    public void setUseClassCriteria(boolean criteria) {
+        _val.setUseClassCriteria(criteria);
+    }
+
+    public int getPolymorphic() {
+        return _val.getPolymorphic();
+    }
+
+    public void setPolymorphic(int poly) {
+        _val.setPolymorphic(poly);
+    }
+
+    public void mapConstraints(String name, boolean adapt) {
+        _val.mapConstraints(name, adapt);
+    }
+
+    public void copyMappingInfo(ValueMapping vm) {
+        _val.copyMappingInfo(vm);
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMapping.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,329 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.util.List;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.Schema;
+import org.apache.openjpa.jdbc.schema.SchemaGroup;
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.jdbc.schema.Unique;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.lib.xml.Commentable;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * Information about the mapping from a field to the schema, in raw form.
+ * The columns and tables used in mapping info will not be part of the
+ * {@link SchemaGroup} used at runtime. Rather, they will be structs
+ * with the relevant pieces of information filled in.
+ *
+ * @author Abe White
+ */
+public class FieldMappingInfo
+    extends MappingInfo
+    implements Commentable {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (FieldMappingInfo.class);
+
+    private String _tableName = null;
+    private boolean _outer = false;
+    private Column _orderCol = null;
+    private boolean _canOrderCol = true;
+    private String[] _comments = null;
+
+    /**
+     * The user-supplied name of the table for this field.
+     */
+    public String getTableName() {
+        return _tableName;
+    }
+
+    /**
+     * The user-supplied name of the table for this field.
+     */
+    public void setTableName(String tableName) {
+        _tableName = tableName;
+    }
+
+    /**
+     * Whether the field's table is joined to the class table through an
+     * outer join.
+     */
+    public boolean isJoinOuter() {
+        return _outer;
+    }
+
+    /**
+     * Whether the field's table is joined to the class table through an
+     * outer join.
+     */
+    public void setJoinOuter(boolean outer) {
+        _outer = outer;
+    }
+
+    /**
+     * Raw synthetic ordering column.
+     */
+    public Column getOrderColumn() {
+        return _orderCol;
+    }
+
+    /**
+     * Raw synthetic ordering column.
+     */
+    public void setOrderColumn(Column order) {
+        _orderCol = order;
+    }
+
+    /**
+     * Whether we can have an ordering column.
+     */
+    public boolean canOrderColumn() {
+        return _canOrderCol;
+    }
+
+    /**
+     * Whether we can have an ordering column.
+     */
+    public void setCanOrderColumn(boolean canOrder) {
+        _canOrderCol = canOrder;
+    }
+
+    /**
+     * Return the table for the given field, or null if no table given.
+     */
+    public Table getTable(final FieldMapping field, boolean create,
+        boolean adapt) {
+        if (_tableName == null && !create)
+            return null;
+
+        Table table = field.getDefiningMapping().getTable();
+        Schema schema = (table == null) ? null : table.getSchema();
+
+        // if we have no join columns defined, there may be class-level join
+        // information with a more fully-qualified name for our table
+        String tableName = _tableName;
+        if (tableName != null && getColumns().isEmpty())
+            tableName = field.getDefiningMapping().getMappingInfo().
+                getSecondaryTableName(tableName);
+
+        return createTable(field, new TableDefaults() {
+            public String get(Schema schema) {
+                // delay this so that we don't do schema reflection for unique
+                // table name unless necessary
+                return field.getMappingRepository().getMappingDefaults().
+                    getTableName(field, schema);
+            }
+        }, schema, tableName, adapt);
+    }
+
+    /**
+     * Return the join from the field table to the owning class table.
+     */
+    public ForeignKey getJoin(final FieldMapping field, Table table,
+        boolean adapt) {
+        // if we have no join columns defined, check class-level join
+        List cols = getColumns();
+        if (cols.isEmpty())
+            cols = field.getDefiningMapping().getMappingInfo().
+                getSecondaryTableJoinColumns(_tableName);
+
+        ForeignKeyDefaults def = new ForeignKeyDefaults() {
+            public ForeignKey get(Table local, Table foreign, boolean inverse) {
+                return field.getMappingRepository().getMappingDefaults().
+                    getJoinForeignKey(field, local, foreign);
+            }
+
+            public void populate(Table local, Table foreign, Column col,
+                Object target, boolean inverse, int pos, int cols) {
+                field.getMappingRepository().getMappingDefaults().
+                    populateJoinColumn(field, local, foreign, col, target,
+                        pos, cols);
+            }
+        };
+        ClassMapping cls = field.getDefiningMapping();
+        return createForeignKey(field, "join", cols, def, table, cls, cls,
+            false, adapt);
+    }
+
+    /**
+     * Unique constraint on the field join.
+     */
+    public Unique getJoinUnique(FieldMapping field, boolean def,
+        boolean adapt) {
+        ForeignKey fk = field.getJoinForeignKey();
+        if (fk == null)
+            return null;
+
+        Unique unq = null;
+        if (fk.getColumns().length > 0)
+            unq = field.getMappingRepository().getMappingDefaults().
+                getJoinUnique(field, fk.getTable(), fk.getColumns());
+        return createUnique(field, "join", unq, fk.getColumns(), adapt);
+    }
+
+    /**
+     * Index on the field join.
+     */
+    public Index getJoinIndex(FieldMapping field, boolean adapt) {
+        ForeignKey fk = field.getJoinForeignKey();
+        if (fk == null)
+            return null;
+
+        Index idx = null;
+        if (fk.getColumns().length > 0)
+            idx = field.getMappingRepository().getMappingDefaults().
+                getJoinIndex(field, fk.getTable(), fk.getColumns());
+        return createIndex(field, "join", idx, fk.getColumns(), adapt);
+    }
+
+    /**
+     * Return the ordering column for this field, or null if none.
+     */
+    public Column getOrderColumn(FieldMapping field, Table table,
+        boolean adapt) {
+        if (_orderCol != null && field.getOrderDeclaration() != null)
+            throw new MetaDataException(_loc.get("order-conflict", field));
+
+        // reset IO
+        setColumnIO(null);
+
+        // has user has explicitly turned ordering off?
+        if (!_canOrderCol || field.getOrderDeclaration() != null)
+            return null;
+
+        // if no defaults return null
+        MappingDefaults def = field.getMappingRepository().
+            getMappingDefaults();
+        if (_orderCol == null && (!adapt && !def.defaultMissingInfo()))
+            return null;
+
+        Column tmplate = new Column();
+        tmplate.setName("ordr");
+        tmplate.setJavaType(JavaTypes.INT);
+        if (!def.populateOrderColumns(field, table, new Column[]{ tmplate })
+            && _orderCol == null)
+            return null;
+
+        if (_orderCol != null && (_orderCol.getFlag(Column.FLAG_UNINSERTABLE)
+            || _orderCol.getFlag(Column.FLAG_UNUPDATABLE))) {
+            ColumnIO io = new ColumnIO();
+            io.setInsertable(0, !_orderCol.getFlag(Column.FLAG_UNINSERTABLE));
+            io.setUpdatable(0, !_orderCol.getFlag(Column.FLAG_UNUPDATABLE));
+            setColumnIO(io);
+        }
+
+        return mergeColumn(field, "order", tmplate, true, _orderCol, table,
+            adapt, def.defaultMissingInfo());
+    }
+
+    /**
+     * Synchronize internal information with the mapping data for the given
+     * field.
+     */
+    public void syncWith(FieldMapping field) {
+        clear(false);
+
+        if (field.getJoinForeignKey() != null)
+            _tableName = field.getMappingRepository().getDBDictionary().
+                getFullName(field.getTable(), true);
+
+        ClassMapping def = field.getDefiningMapping();
+        setColumnIO(field.getJoinColumnIO());
+        if (field.getJoinForeignKey() != null && def.getTable() != null)
+            syncForeignKey(field, field.getJoinForeignKey(),
+                field.getTable(), def.getTable());
+        _outer = field.isJoinOuter();
+
+        syncIndex(field, field.getJoinIndex());
+        syncUnique(field, field.getJoinUnique());
+        syncOrderColumn(field);
+        syncStrategy(field);
+    }
+
+    /**
+     * Synchronize internal mapping strategy information with the given field.
+     */
+    public void syncStrategy(FieldMapping field) {
+        setStrategy(null);
+        if (field.getHandler() != null || field.getStrategy() == null)
+            return;
+
+        // explicit strategy if the strategy isn't the expected default
+        Strategy strat = field.getMappingRepository().defaultStrategy
+            (field, false);
+        if (strat == null || !strat.getAlias().equals(field.getAlias()))
+            setStrategy(field.getAlias());
+    }
+
+    /**
+     * Synchronize internal order column information with the given field.
+     */
+    public void syncOrderColumn(FieldMapping field) {
+        if (field.getOrderColumn() != null)
+            _orderCol = syncColumn(field, field.getOrderColumn(), 1, false,
+                field.getTable(), null, null, false);
+        else
+            _orderCol = null;
+    }
+
+    public boolean hasSchemaComponents() {
+        return super.hasSchemaComponents() || _tableName != null
+            || _orderCol != null;
+    }
+
+    protected void clear(boolean canFlags) {
+        super.clear(canFlags);
+        _tableName = null;
+        _orderCol = null;
+        if (canFlags)
+            _canOrderCol = true;
+    }
+
+    public void copy(MappingInfo info) {
+        super.copy(info);
+        if (!(info instanceof FieldMappingInfo))
+            return;
+
+        FieldMappingInfo finfo = (FieldMappingInfo) info;
+        if (_tableName == null)
+            _tableName = finfo.getTableName();
+        if (!_outer)
+            _outer = finfo.isJoinOuter();
+        if (_canOrderCol && _orderCol == null)
+            _canOrderCol = finfo.canOrderColumn();
+        if (_canOrderCol && finfo.getOrderColumn() != null) {
+            if (_orderCol == null)
+                _orderCol = new Column();
+            _orderCol.copy(finfo.getOrderColumn());
+        }
+    }
+
+    public String[] getComments() {
+        return (_comments == null) ? EMPTY_COMMENTS : _comments;
+    }
+
+    public void setComments(String[] comments) {
+        _comments = comments;
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldMappingInfo.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldStrategy.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldStrategy.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldStrategy.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.RowManager;
+import org.apache.openjpa.jdbc.sql.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.jdbc.sql.SelectExecutor;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+/**
+ * Maps a persistent field to the relational schema.
+ *
+ * @author Abe White
+ * @since 4.0
+ */
+public interface FieldStrategy
+    extends Strategy {
+
+    /**
+     * Set the class mapping using this strategy. This will be called before
+     * use.
+     */
+    public void setFieldMapping(FieldMapping owner);
+
+    /**
+     * Return whether this mapping can perform the given select type.
+     * Return 0 if the given type is not supported. If the given type is an
+     * eager parallel type, return the number of UNIONed selects necessary
+     * to fetch the data. Otherwise, return any positive number if the type
+     * is supported. The given state manager may be null if selecting
+     * multiple instances.
+     *
+     * @see Select
+     */
+    public int supportsSelect(Select sel, int type, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchConfiguration fetch);
+
+    /**
+     * Fill in parallel eager select for related objects.
+     *
+     * @see #select
+     */
+    public void selectEagerParallel(SelectExecutor sel, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchState fetchState, int eagerMode);
+
+    /**
+     * Fill in joined select to related objects.
+     *
+     * @see #select
+     */
+    public void selectEagerJoin(Select sel, OpenJPAStateManager sm,
+        JDBCStore store, JDBCFetchState fetchState, int eagerMode);
+
+    /**
+     * Whether the eager joins or selects used by this field are to-many.
+     */
+    public boolean isEagerSelectToMany();
+
+    /**
+     * Select the virtual row columns of this mapping.
+     *
+     * @param sel the select to add to
+     * @param sm the instance being loaded, or null if not
+     * initialized yet or selecting for multiple instances
+     * @param store the current store manager
+     * @param fetch fetch configuration
+     * @param eagerMode the eager fetch mode to use; this may be more
+     * restrictive than the mode of the fetch configuration
+     * @return &gt; 0 if this mapping requires the selected data
+     * (if any), 0 if it selected data but does not
+     * require it, or &lt; 0 if no data was selected
+     */
+    public int select(Select sel, OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, int eagerMode);
+
+    /**
+     * Load the batched eager result.
+     *
+     * @param res originally the {@link Result} to load from, but this
+     * method may return a processed result form that will be
+     * passed to subsequent calls
+     */
+    public Object loadEagerParallel(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Object res)
+        throws SQLException;
+
+    /**
+     * Load the joined eager result.
+     */
+    public void loadEagerJoin(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Result res)
+        throws SQLException;
+
+    /**
+     * Load virtual row data; the given result is not guaranteed to contain
+     * data for this field, so the field mapping should make sure the
+     * result contains its needed column data before loading.
+     */
+    public void load(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState, Result res)
+        throws SQLException;
+
+    /**
+     * Load secondary data using a connection from the store manager.
+     */
+    public void load(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException;
+
+    ///////////
+    // Queries
+    ///////////
+
+    /**
+     * Translate the given external field value to its datastore equivalent.
+     * If the mapping occupies multiple columns in the datastore, return an
+     * object array, else return a single object. Simply returns the given
+     * object by default.
+     */
+    public Object toDataStoreValue(Object val, JDBCStore store);
+
+    /**
+     * Translate the given key value to its datastore equivalent. If the
+     * mapping occupies multiple columns in the datastore, return an object
+     * array, else return a single object. Simply returns the given object by
+     * default.
+     */
+    public Object toKeyDataStoreValue(Object val, JDBCStore store);
+
+    /**
+     * Append a where clause to the given statement checking if this value
+     * is empty. Appends impossible-to-satisfy SQL by default.
+     */
+    public void appendIsEmpty(SQLBuffer sql, Select sel, Joins joins);
+
+    /**
+     * Append a where clause to the given statement checking if this value
+     * is not empty. Appends always-satisfied SQL by default.
+     */
+    public void appendIsNotEmpty(SQLBuffer sql, Select sel, Joins joins);
+
+    /**
+     * Append a where clause to the given statement checking if this value
+     * is null.
+     */
+    public void appendIsNull(SQLBuffer sql, Select sel, Joins joins);
+
+    /**
+     * Append a where clause to the given statement checking if this value
+     * is not null.
+     */
+    public void appendIsNotNull(SQLBuffer sql, Select sel, Joins joins);
+
+    /**
+     * Append a where clause to the given statement checking the size
+     * of the value.
+     */
+    public void appendSize(SQLBuffer sql, Select sel, Joins joins);
+
+    /**
+     * Join this value to the class table. Does nothing by default.
+     */
+    public Joins join(Joins joins, boolean forceOuter);
+
+    /**
+     * Join the key value to the class table. Does nothing by default.
+     */
+    public Joins joinKey(Joins joins, boolean forceOuter);
+
+    /**
+     * Join this value's table to the table for the related first class object
+     * type, if any. Does nothing by default.
+     *
+     * @param traverse if true, throw proper exception if it is not
+     * possible for this mapping to traverse into the related type
+     */
+    public Joins joinRelation(Joins joins, boolean forceOuter,
+        boolean traverse);
+
+    /**
+     * Join this value's table to the table for the related first class object
+     * key type, if any. Does nothing by default.
+     *
+     * @param traverse if true, throw proper exception if it is not
+     * possible for this mapping to traverse into the related type
+     */
+    public Joins joinKeyRelation(Joins joins, boolean forceOuter,
+        boolean traverse);
+
+    /**
+     * Load this field value using the given result. The result
+     * will contain the columns from {@link ValueMapping#getColumns}.
+     */
+    public Object loadProjection(JDBCStore store, JDBCFetchState fetchState,
+        Result res, Joins joins)
+        throws SQLException;
+
+    /**
+     * Load this field's key value using the given result. The result will
+     * contain the columns from {@link ValueMapping#getColumns}.
+     */
+    public Object loadKeyProjection(JDBCStore store,
+        JDBCFetchState fetchState, Result res, Joins joins)
+        throws SQLException;
+
+    //////////////
+    // Versioning
+    //////////////
+
+    /**
+     * Return true if this field can be used as part of a state image for
+     * optimistic locking.
+     */
+    public boolean isVersionable();
+
+    /**
+     * Add a WHERE condition to the row for this field such that the field's
+     * current DB value must equal the given previous value. Only versionable
+     * mappings must implement this method meaningfully.
+     */
+    public void where(OpenJPAStateManager sm, JDBCStore store, RowManager rm,
+        Object prevValue)
+        throws SQLException;
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/FieldStrategy.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCColumnOrder.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCColumnOrder.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCColumnOrder.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCColumnOrder.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.util.Comparator;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Select;
+
+/**
+ * Order by a synthetic order column.
+ *
+ * @author Abe White
+ */
+class JDBCColumnOrder
+    implements JDBCOrder {
+
+    private Column _col = null;
+    private ColumnIO _io = null;
+
+    /**
+     * The synthetic column.
+     */
+    public Column getColumn() {
+        return _col;
+    }
+
+    /**
+     * The synthetic column.
+     */
+    public void setColumn(Column col) {
+        _col = col;
+    }
+
+    /**
+     * I/O restrictions for the synthetic column.
+     */
+    public ColumnIO getColumnIO() {
+        return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
+    }
+
+    /**
+     * I/O restrictions for the synthetic column.
+     */
+    public void setColumnIO(ColumnIO io) {
+        _io = io;
+    }
+
+    public String getName() {
+        return (_col == null) ? "" : _col.getName();
+    }
+
+    public boolean isAscending() {
+        return true;
+    }
+
+    public Comparator getComparator() {
+        return null;
+    }
+
+    public boolean isInRelation() {
+        return false;
+    }
+
+    public void order(Select sel, ClassMapping elem, Joins joins) {
+        if (_col != null)
+            sel.orderBy(_col, true, joins, true);
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCColumnOrder.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCOrder.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCOrder.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCOrder.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCOrder.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.meta.Order;
+
+/**
+ * Order in the datastore using JDBC.
+ *
+ * @author Abe White
+ */
+interface JDBCOrder
+    extends Order {
+
+    /**
+     * Whether the value is a member of the field's related type, rather than
+     * columns of the field itself.
+     */
+    public boolean isInRelation();
+
+    /**
+     * Order by this value.
+     *
+     * @param elem if this value has independent mappings, the mapping
+     * we're selecting
+     */
+    public void order(Select sel, ClassMapping elem, Joins joins);
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCOrder.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCRelatedFieldOrder.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCRelatedFieldOrder.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCRelatedFieldOrder.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCRelatedFieldOrder.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.util.Comparator;
+
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * Use the database to order by a field in the related type.
+ *
+ * @author Abe White
+ */
+class JDBCRelatedFieldOrder
+    implements JDBCOrder {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (JDBCRelatedFieldOrder.class);
+
+    private final FieldMapping _fm;
+    private final boolean _asc;
+
+    public JDBCRelatedFieldOrder(FieldMapping owner, FieldMapping rel,
+        boolean asc) {
+        if (!rel.isInDefaultFetchGroup())
+            throw new MetaDataException(_loc.get("nondfg-field-orderable",
+                owner, rel.getName()));
+
+        _fm = rel;
+        _asc = asc;
+    }
+
+    public String getName() {
+        return _fm.getName();
+    }
+
+    public boolean isAscending() {
+        return _asc;
+    }
+
+    public Comparator getComparator() {
+        return null;
+    }
+
+    public boolean isInRelation() {
+        return true;
+    }
+
+    public void order(Select sel, ClassMapping elem, Joins joins) {
+        FieldMapping fm = elem.getFieldMapping(_fm.getIndex());
+        sel.orderBy(fm.getColumns(), _asc, joins, false);
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/JDBCRelatedFieldOrder.java
------------------------------------------------------------------------------
    svn:executable = *