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 [10/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/kernel/exps/ToLowerCase.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToLowerCase.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToLowerCase.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToLowerCase.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,49 @@
+/*
+ * 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.kernel.exps;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.Select;
+
+/**
+ * Lower-cases a string.
+ *
+ * @author Abe White
+ */
+class ToLowerCase
+    extends StringFunction {
+
+    /**
+     * Constructor. Provide the string to operate on.
+     */
+    public ToLowerCase(Val val) {
+        super(val);
+    }
+
+    public void initialize(Select sel, JDBCStore store, boolean nullTest) {
+        _val.initialize(sel, store, false);
+
+        DBDictionary dict = store.getDBDictionary();
+        String func = dict.toLowerCaseFunction;
+        dict.assertSupport(func != null, "ToLowerCaseFunction");
+
+        int idx = func.indexOf("{0}");
+        _pre = func.substring(0, idx);
+        _post = func.substring(idx + 3);
+    }
+}
+

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToLowerCase.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToUpperCase.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToUpperCase.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToUpperCase.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToUpperCase.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,49 @@
+/*
+ * 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.kernel.exps;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.jdbc.sql.Select;
+
+/**
+ * Upper-cases a string.
+ *
+ * @author Abe White
+ */
+class ToUpperCase
+    extends StringFunction {
+
+    /**
+     * Constructor. Provide the string to operate on.
+     */
+    public ToUpperCase(Val val) {
+        super(val);
+    }
+
+    public void initialize(Select sel, JDBCStore store, boolean nullTest) {
+        _val.initialize(sel, store, false);
+
+        DBDictionary dict = store.getDBDictionary();
+        String func = dict.toUpperCaseFunction;
+        dict.assertSupport(func != null, "ToUpperCaseFunction");
+
+        int idx = func.indexOf("{0}");
+        _pre = func.substring(0, idx);
+        _post = func.substring(idx + 3);
+    }
+}
+

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/ToUpperCase.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Trim.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Trim.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Trim.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Trim.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,196 @@
+/*
+ * 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.kernel.exps;
+
+import java.lang.Math;
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+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;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.kernel.exps.Literal;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Returns the number of characters in a string.
+ *
+ * @author Marc Prud'hommeaux
+ */
+class Trim
+    extends AbstractVal
+    implements Val {
+
+    private final Val _val;
+    private final Val _trimChar;
+    private final Boolean _where;
+    private ClassMetaData _meta = null;
+    private String _func = null;
+
+    /**
+     * Constructor. Provide the string to operate on.
+     */
+    public Trim(Val val, Val trimChar, Boolean where) {
+        _val = val;
+        _trimChar = trimChar;
+        _where = where;
+    }
+
+    public ClassMetaData getMetaData() {
+        return _meta;
+    }
+
+    public void setMetaData(ClassMetaData meta) {
+        _meta = meta;
+    }
+
+    public boolean isVariable() {
+        return false;
+    }
+
+    public Class getType() {
+        return String.class;
+    }
+
+    public void setImplicitType(Class type) {
+    }
+
+    public void initialize(Select sel, JDBCStore store, boolean nullTest) {
+        _val.initialize(sel, store, false);
+
+        DBDictionary dict = store.getDBDictionary();
+        if (_where == null) {
+            _func = dict.trimBothFunction;
+            dict.assertSupport(_func != null, "TrimBothFunction");
+        } else if (_where.equals(Boolean.TRUE)) {
+            _func = dict.trimLeadingFunction;
+            dict.assertSupport(_func != null, "TrimLeadingFunction");
+        } else if (_where.equals(Boolean.FALSE)) {
+            _func = dict.trimTrailingFunction;
+            dict.assertSupport(_func != null, "TrimTrailingFunction");
+        }
+    }
+
+    public Joins getJoins() {
+        return _val.getJoins();
+    }
+
+    public Object toDataStoreValue(Object val, JDBCStore store) {
+        return val;
+    }
+
+    public void select(Select sel, JDBCStore store, Object[] params,
+        boolean pks, JDBCFetchState fetchState) {
+        sel.select(newSQLBuffer(sel, store, params, fetchState), this);
+    }
+
+    public void selectColumns(Select sel, JDBCStore store,
+        Object[] params, boolean pks, JDBCFetchState fetchState) {
+        _val.selectColumns(sel, store, params, true, fetchState);
+    }
+
+    public void groupBy(Select sel, JDBCStore store, Object[] params,
+        JDBCFetchState fetchState) {
+        sel.groupBy(newSQLBuffer(sel, store, params, fetchState), false);
+    }
+
+    public void orderBy(Select sel, JDBCStore store, Object[] params,
+        boolean asc, JDBCFetchState fetchState) {
+        sel.orderBy(newSQLBuffer(sel, store, params, fetchState), asc, false);
+    }
+
+    private SQLBuffer newSQLBuffer(Select sel, JDBCStore store,
+        Object[] params, JDBCFetchState fetchState) {
+        calculateValue(sel, store, params, null, fetchState);
+        SQLBuffer buf = new SQLBuffer(store.getDBDictionary());
+        appendTo(buf, 0, sel, store, params, fetchState);
+        clearParameters();
+        return buf;
+    }
+
+    public Object load(Result res, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException {
+        return Filters.convert(res.getObject(this,
+            JavaSQLTypes.JDBC_DEFAULT, null), getType());
+    }
+
+    public boolean hasVariable(Variable var) {
+        return _val.hasVariable(var);
+    }
+
+    public void calculateValue(Select sel, JDBCStore store,
+        Object[] params, Val other, JDBCFetchState fetchState) {
+        _val.calculateValue(sel, store, params, null, fetchState);
+    }
+
+    public void clearParameters() {
+        _val.clearParameters();
+    }
+
+    public int length() {
+        return 1;
+    }
+
+    public void appendTo(SQLBuffer sql, int index, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+        _val.calculateValue(sel, store, params, _trimChar, fetchState);
+        _trimChar.calculateValue(sel, store, params, _val, fetchState);
+
+        int fromPart = _func.indexOf("{0}");
+        int charPart = _func.indexOf("{1}");
+
+        if (charPart == -1)
+            charPart = _func.length();
+
+        String part1 = _func.substring(0, Math.min(fromPart, charPart));
+
+        String part2 = _func.substring(Math.min(fromPart, charPart) + 3,
+            Math.max(fromPart, charPart));
+
+        String part3 = null;
+        if (charPart != _func.length())
+            part3 = _func.substring(Math.max(fromPart, charPart) + 3);
+
+        sql.append(part1);
+        (fromPart < charPart ? _val : _trimChar).
+            appendTo(sql, 0, sel, store, params, fetchState);
+        sql.append(part2);
+
+        if (charPart != _func.length()) {
+            (fromPart > charPart ? _val : _trimChar).
+                appendTo(sql, 0, sel, store, params, fetchState);
+            sql.append(part3);
+        } else {
+            // since the trim statement did not specify the token for
+            // where to specify the trim char (denoted by "{1}"),
+            // we do not have the ability to trim off non-whitespace
+            // characters; throw an exception when we attempt to do so
+            if (!(_trimChar instanceof Literal)
+                || String.valueOf(((Literal) _trimChar).getValue()).
+                trim().length() != 0) {
+                store.getDBDictionary().assertSupport(false,
+                    "TrimNonWhitespaceCharacters");
+            }
+        }
+    }
+}
+

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Trim.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/UnaryOp.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/UnaryOp.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/UnaryOp.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/UnaryOp.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,171 @@
+/*
+ * 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.kernel.exps;
+
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
+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;
+import org.apache.openjpa.kernel.Filters;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * Value produced by a unary operation on a value.
+ *
+ * @author Abe White
+ */
+abstract class UnaryOp
+    extends AbstractVal
+    implements Val {
+
+    private final Val _val;
+    private ClassMetaData _meta = null;
+    private Class _cast = null;
+
+    /**
+     * Constructor. Provide the value to operate on.
+     */
+    public UnaryOp(Val val) {
+        _val = val;
+    }
+
+    protected Val getVal() {
+        return _val;
+    }
+
+    public ClassMetaData getMetaData() {
+        return _meta;
+    }
+
+    public void setMetaData(ClassMetaData meta) {
+        _meta = meta;
+    }
+
+    public boolean isVariable() {
+        return false;
+    }
+
+    public Class getType() {
+        if (_cast != null)
+            return _cast;
+        return getType(_val.getType());
+    }
+
+    public void setImplicitType(Class type) {
+        _cast = type;
+    }
+
+    public void initialize(Select sel, JDBCStore store, boolean nullTest) {
+        _val.initialize(sel, store, false);
+    }
+
+    public Joins getJoins() {
+        return _val.getJoins();
+    }
+
+    public Object toDataStoreValue(Object val, JDBCStore store) {
+        return val;
+    }
+
+    public void select(Select sel, JDBCStore store, Object[] params,
+        boolean pks, JDBCFetchState fetchState) {
+        sel.select(newSQLBuffer(sel, store, params, fetchState), this);
+        if (isAggregate())
+            sel.setAggregate(true);
+    }
+
+    public void selectColumns(Select sel, JDBCStore store,
+        Object[] params, boolean pks, JDBCFetchState fetchState) {
+        _val.selectColumns(sel, store, params, true, fetchState);
+    }
+
+    public void groupBy(Select sel, JDBCStore store, Object[] params,
+        JDBCFetchState fetchState) {
+        sel.groupBy(newSQLBuffer(sel, store, params, fetchState), false);
+    }
+
+    public void orderBy(Select sel, JDBCStore store, Object[] params,
+        boolean asc, JDBCFetchState fetchState) {
+        sel.orderBy(newSQLBuffer(sel, store, params, fetchState), asc, false);
+    }
+
+    private SQLBuffer newSQLBuffer(Select sel, JDBCStore store,
+        Object[] params, JDBCFetchState fetchState) {
+        calculateValue(sel, store, params, null, fetchState);
+        SQLBuffer buf = new SQLBuffer(store.getDBDictionary());
+        appendTo(buf, 0, sel, store, params, fetchState);
+        clearParameters();
+        return buf;
+    }
+
+    public Object load(Result res, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException {
+        return Filters.convert(res.getObject(this,
+            JavaSQLTypes.JDBC_DEFAULT, null), getType());
+    }
+
+    public boolean hasVariable(Variable var) {
+        return _val.hasVariable(var);
+    }
+
+    public void calculateValue(Select sel, JDBCStore store,
+        Object[] params, Val other, JDBCFetchState fetchState) {
+        _val.calculateValue(sel, store, params, null, fetchState);
+    }
+
+    public void clearParameters() {
+        _val.clearParameters();
+    }
+
+    public int length() {
+        return 1;
+    }
+
+    public void appendTo(SQLBuffer sql, int index, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+        sql.append(getOperator());
+        sql.append("(");
+        _val.appendTo(sql, 0, sel, store, params, fetchState);
+        sql.append(")");
+    }
+
+    /**
+     * Return whether this operator is an aggregate.
+     */
+    protected boolean isAggregate() {
+        return false;
+    }
+
+    /**
+     * Return the type of this value based on the argument type. Returns
+     * the argument type by default.
+     */
+    protected Class getType(Class c) {
+        return c;
+    }
+
+    /**
+     * Return the name of this operator.
+     */
+    protected abstract String getOperator();
+}
+

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/UnaryOp.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Val.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Val.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Val.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Val.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,161 @@
+/*
+ * 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.kernel.exps;
+
+import java.sql.SQLException;
+
+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.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.exps.Value;
+
+/**
+ * A Value represents any non-operator in a query filter, including
+ * constants, variables, and object fields.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public interface Val
+    extends Value {
+
+    /**
+     * Initialize the value. This method should recursively initialize any
+     * sub-values. It should also cache the {@link Joins} instance
+     * containing the joins for this value. No additional joins should be
+     * made after this call. The parent expression might modify these joins
+     * during its own initialization so that common joins are moved up the
+     * expression tree. These joins should not be included in the SQL
+     * appended through any of the <code>append</code> methods.
+     *
+     * @param sel used to create {@link Joins} instances
+     * @param store the store manager for the query
+     * @param nullTest if true, then this value will be compared
+     * to null or tested for emptiness
+     */
+    public void initialize(Select sel, JDBCStore store, boolean nullTest);
+
+    /**
+     * Return the joins for this value. These joins should be created
+     * and cached during the {@link #initialize} method. The parent
+     * expression might modify these joins during its own initialization so
+     * that common joins are moved up the expression tree.
+     */
+    public Joins getJoins();
+
+    /**
+     * Return the datastore value of the given object in the context of this
+     * value.
+     */
+    public Object toDataStoreValue(Object val, JDBCStore store);
+
+    /**
+     * Select the data for this value.
+     */
+    public void select(Select sel, JDBCStore store, Object[] params,
+        boolean pks, JDBCFetchState fetchState);
+
+    /**
+     * Select just the columns for this value.
+     */
+    public void selectColumns(Select sel, JDBCStore store, Object[] params,
+        boolean pks, JDBCFetchState fetchState);
+
+    /**
+     * Group by this value.
+     */
+    public void groupBy(Select sel, JDBCStore store, Object[] params,
+        JDBCFetchState fetchState);
+
+    /**
+     * Order by this value.
+     */
+    public void orderBy(Select sel, JDBCStore store, Object[] params,
+        boolean asc, JDBCFetchState fetchState);
+
+    /**
+     * Load the data for this value.
+     */
+    public Object load(Result res, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException;
+
+    /**
+     * Return true if this value uses the given variable.
+     */
+    public boolean hasVariable(Variable var);
+
+    /**
+     * Calculate and cache the SQL for this value. This method is called
+     * before <code>length</code> or any <code>append</code> methods.
+     *
+     * @param other the value being compared to, or null if not a comparison
+     */
+    public void calculateValue(Select sel, JDBCStore store,
+        Object[] params, Val other, JDBCFetchState fetchState);
+
+    /**
+     * Clear parameter values held by this value or its subcomponents.
+     * This method is called sometime after <code>calculateValue</code>.
+     */
+    public void clearParameters();
+
+    /**
+     * Return the number of SQL elements in this value.
+     */
+    public int length();
+
+    /**
+     * Append the <code>index</code>th SQL element to the given buffer.
+     */
+    public void appendTo(SQLBuffer sql, int index, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState);
+
+    /**
+     * Append the SQL testing whether this value is empty to the given buffer.
+     */
+    public void appendIsEmpty(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState);
+
+    /**
+     * Append the SQL testing whether this value is not empty to
+     * the given buffer.
+     */
+    public void appendIsNotEmpty(SQLBuffer sql, Select sel, JDBCStore store,
+        Object[] params, JDBCFetchState fetchState);
+
+    /**
+     * Append the SQL checking the size of this value.
+     */
+    public void appendSize(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState);
+
+    /**
+     * Append the SQL testing whether this value is null to the given buffer.
+     */
+    public void appendIsNull(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState);
+
+    /**
+     * Append the SQL testing whether this value is not null to the given
+     * buffer.
+     */
+    public void appendIsNotNull(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState);
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Val.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Variable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Variable.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Variable.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Variable.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,188 @@
+/*
+ * 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.kernel.exps;
+
+import java.sql.SQLException;
+
+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.SQLBuffer;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.meta.ClassMetaData;
+
+/**
+ * A variable in a filter. Typically, the {@link #initialize} and
+ * {@link #getJoins} methods of this value are not called. They are
+ * only called if the variable is bound but otherwise unused in the filter,
+ * in which case we must at least make the joins to the variable because the
+ * act of binding a variable should at least guarantee that an instance
+ * represting the variable could exist (i.e. the binding collection is not
+ * empty).
+ *
+ * @author Abe White
+ */
+class Variable
+    implements Val {
+
+    private final String _name;
+    private final Class _type;
+    private ClassMetaData _meta;
+    private PCPath _path = null;
+    private Class _cast = null;
+
+    /**
+     * Constructor. Supply variable name and type.
+     */
+    public Variable(String name, Class type) {
+        _name = name;
+        _type = type;
+    }
+
+    /**
+     * Return the variable name.
+     */
+    public String getName() {
+        return _name;
+    }
+
+    /**
+     * Return true if the variable is bound.
+     */
+    public boolean isBound() {
+        return _path != null;
+    }
+
+    /**
+     * Return the path this variable is aliased to.
+     */
+    public PCPath getPCPath() {
+        return _path;
+    }
+
+    /**
+     * Set the path this variable is aliased to.
+     */
+    public void setPCPath(PCPath path) {
+        _path = path;
+    }
+
+    public ClassMetaData getMetaData() {
+        return _meta;
+    }
+
+    public void setMetaData(ClassMetaData meta) {
+        _meta = meta;
+    }
+
+    public boolean isVariable() {
+        return true;
+    }
+
+    public Class getType() {
+        if (_cast != null)
+            return _cast;
+        return _type;
+    }
+
+    public void setImplicitType(Class type) {
+        _cast = type;
+        if (_path != null)
+            _path.setImplicitType(type);
+    }
+
+    public void initialize(Select sel, JDBCStore store, boolean nullTest) {
+        if (_path != null) {
+            _path.addVariableAction(this);
+            _path.initialize(sel, store, nullTest);
+            _path.joinRelation();
+        }
+    }
+
+    public Joins getJoins() {
+        return (_path == null) ? null : _path.getJoins();
+    }
+
+    public Object toDataStoreValue(Object val, JDBCStore store) {
+        return val;
+    }
+
+    public void select(Select sel, JDBCStore store, Object[] params,
+        boolean pks, JDBCFetchState fetchState) {
+    }
+
+    public void selectColumns(Select sel, JDBCStore store,
+        Object[] params, boolean pks, JDBCFetchState fetchState) {
+    }
+
+    public void groupBy(Select sel, JDBCStore store, Object[] params,
+        JDBCFetchState fetchState) {
+    }
+
+    public void orderBy(Select sel, JDBCStore store, Object[] params,
+        boolean asc, JDBCFetchState fetchState) {
+    }
+
+    public Object load(Result res, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException {
+        return null;
+    }
+
+    public boolean hasVariable(Variable var) {
+        return this == var;
+    }
+
+    public void calculateValue(Select sel, JDBCStore store,
+        Object[] params, Val other, JDBCFetchState fetchState) {
+        if (_path != null)
+            _path.calculateValue(sel, store, params, other, fetchState);
+    }
+
+    public void clearParameters() {
+        if (_path != null)
+            _path.clearParameters();
+    }
+
+    public int length() {
+        return 0;
+    }
+
+    public void appendTo(SQLBuffer sql, int index, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+
+    public void appendIsEmpty(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+
+    public void appendIsNotEmpty(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+
+    public void appendSize(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+
+    public void appendIsNull(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+
+    public void appendIsNotNull(SQLBuffer sql, Select sel,
+        JDBCStore store, Object[] params, JDBCFetchState fetchState) {
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/Variable.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/package.html
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/package.html?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/package.html (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/package.html Wed Jul 19 14:34:44 2006
@@ -0,0 +1,5 @@
+<html>
+<body>
+<p><strong>OpenJPA-JDBC Expression Tree</strong></p>
+</body>
+</html>

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/exps/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/package.html
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/package.html?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/package.html (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/package.html Wed Jul 19 14:34:44 2006
@@ -0,0 +1,9 @@
+<html>
+<body>
+<p><strong>OpenJPA-JDBC Runtime Kernel</strong></p>
+
+<p>
+    Runtime services for the JDBC OpenJPA implementation.
+</p>
+</body>
+</html>

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/package.html
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMapping.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,957 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.set.ListOrderedSet;
+import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.strats.NoneClassStrategy;
+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.Schemas;
+import org.apache.openjpa.jdbc.schema.Table;
+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.Select;
+import org.apache.openjpa.kernel.FetchConfiguration;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.PCState;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.meta.ClassMetaData;
+import org.apache.openjpa.meta.ValueMetaData;
+import org.apache.openjpa.util.ApplicationIds;
+import org.apache.openjpa.util.InternalException;
+import org.apache.openjpa.util.MetaDataException;
+import org.apache.openjpa.util.OpenJPAId;
+
+/**
+ * Specialization of metadata for relational databases.
+ *
+ * @author Abe White
+ */
+public class ClassMapping
+    extends ClassMetaData
+    implements ClassStrategy {
+
+    public static final ClassMapping[] EMPTY_MAPPINGS = new ClassMapping[0];
+
+    private static final Localizer _loc = Localizer.forPackage
+        (ClassMapping.class);
+
+    private final ClassMappingInfo _info;
+    private final Discriminator _discrim;
+    private final Version _version;
+    private ClassStrategy _strategy = null;
+
+    private Table _table = null;
+    private ColumnIO _io = null;
+    private Column[] _cols = Schemas.EMPTY_COLUMNS;
+    private ForeignKey _fk = null;
+    private int _subclassMode = Integer.MAX_VALUE;
+
+    private ClassMapping[] _joinSubMaps = null;
+    private ClassMapping[] _assignMaps = null;
+
+    // maps columns to joinables
+    private final Map _joinables = Collections.synchronizedMap(new HashMap());
+
+    /**
+     * Constructor. Supply described type and owning repository.
+     */
+    protected ClassMapping(Class type, MappingRepository repos) {
+        super(type, repos);
+        _discrim = repos.newDiscriminator(this);
+        _version = repos.newVersion(this);
+        _info = repos.newMappingInfo(this);
+    }
+
+    /**
+     * Embedded constructor. Supply embedding value and owning repository.
+     */
+    protected ClassMapping(ValueMetaData vmd) {
+        super(vmd);
+        _discrim = getMappingRepository().newDiscriminator(this);
+        _version = getMappingRepository().newVersion(this);
+        _info = getMappingRepository().newMappingInfo(this);
+    }
+
+    /**
+     * The class discriminator.
+     */
+    public Discriminator getDiscriminator() {
+        return _discrim;
+    }
+
+    /**
+     * The version indicator.
+     */
+    public Version getVersion() {
+        return _version;
+    }
+
+    ///////////
+    // Runtime
+    ///////////
+
+    /**
+     * Return the oid value stored in the result. This implementation will
+     * recurse until it finds an ancestor class who uses oid values for its
+     * primary key.
+     *
+     * @param fk if non-null, use the local columns of the given foreign
+     * key in place of this class' primary key columns
+     * @see #isPrimaryKeyObjectId
+     */
+    public Object getObjectId(JDBCStore store, Result res, ForeignKey fk,
+        boolean subs, Joins joins)
+        throws SQLException {
+        ValueMapping embed = getEmbeddingMapping();
+        if (embed != null)
+            return embed.getFieldMapping().getDefiningMapping().
+                getObjectId(store, res, fk, subs, joins);
+
+        return getObjectId(this, store, res, fk, subs, joins);
+    }
+
+    /**
+     * Recursive helper for public <code>getObjectId</code> method.
+     */
+    private Object getObjectId(ClassMapping cls, JDBCStore store, Result res,
+        ForeignKey fk, boolean subs, Joins joins)
+        throws SQLException {
+        if (!isPrimaryKeyObjectId(true))
+            return getPCSuperclassMapping().getObjectId(cls, store, res, fk,
+                subs, joins);
+        if (getIdentityType() == ID_UNKNOWN)
+            throw new InternalException();
+
+        Column[] pks = getPrimaryKeyColumns();
+        if (getIdentityType() == ID_DATASTORE) {
+            Column col = (fk == null) ? pks[0] : fk.getColumn(pks[0]);
+            long id = res.getLong(col, joins);
+            return (id == 0 && res.wasNull()) ? null
+                : store.newDataStoreId(id, cls, subs);
+        }
+
+        // application identity
+        Object[] vals = new Object[getPrimaryKeyFields().length];
+        FieldMapping fm;
+        Joinable join;
+        int pkIdx;
+        for (int i = 0; i < pks.length; i++) {
+            // we know that all pk column join mappings use primary key fields,
+            // cause this mapping uses the oid as its primary key (we recursed
+            // at the beginning of the method to ensure this)
+            join = assertJoinable(pks[i]);
+            fm = getFieldMapping(join.getFieldIndex());
+            pkIdx = fm.getPrimaryKeyIndex();
+
+            // could have already set value with previous multi-column joinable
+            if (vals[pkIdx] == null) {
+                res.startDataRequest(fm);
+                vals[pkIdx] = join.getPrimaryKeyValue(res, join.getColumns(),
+                    fk, joins);
+                res.endDataRequest();
+                if (vals[pkIdx] == null)
+                    return null;
+            }
+        }
+        Object oid = ApplicationIds.fromPKValues(vals, cls);
+        if (!subs && oid instanceof OpenJPAId)
+            ((OpenJPAId) oid).setManagedInstanceType(cls.getDescribedType());
+        return oid;
+    }
+
+    /**
+     * Return the given column value(s) for the given object. The given
+     * columns will be primary key columns of this mapping, but may be in
+     * any order. If there is only one column, return its value. If there
+     * are multiple columns, return an object array of their values, in the
+     * same order the columns are given.
+     */
+    public Object toDataStoreValue(Object obj, Column[] cols, JDBCStore store) {
+        Object ret = (cols.length == 1) ? null : new Object[cols.length];
+
+        // in the past we've been lenient about being able to translate objects
+        // from other persistence contexts, so try to get sm directly from
+        // instance before asking our context
+        OpenJPAStateManager sm;
+        if (obj instanceof PersistenceCapable)
+            sm = (OpenJPAStateManager) ((PersistenceCapable) obj).
+                pcGetStateManager();
+        else
+            sm = store.getContext().getStateManager(obj);
+        if (sm == null)
+            return ret;
+
+        Object val;
+        for (int i = 0; i < cols.length; i++) {
+            val = assertJoinable(cols[i]).getJoinValue(sm, cols[i], store);
+            if (cols.length == 1)
+                ret = val;
+            else
+                ((Object[]) ret)[i] = val;
+        }
+        return ret;
+    }
+
+    /**
+     * Return the joinable for the given column, or throw an exception if
+     * none is available.
+     */
+    public Joinable assertJoinable(Column col) {
+        Joinable join = getJoinable(col);
+        if (join == null)
+            throw new MetaDataException(_loc.get("no-joinable",
+                col.getFullName()));
+        return join;
+    }
+
+    /**
+     * Return the {@link Joinable} for the given column. Any column that
+     * another mapping joins to must be controlled by a joinable.
+     */
+    public Joinable getJoinable(Column col) {
+        Joinable join;
+        if (getEmbeddingMetaData() != null) {
+            join = getEmbeddingMapping().getFieldMapping().
+                getDefiningMapping().getJoinable(col);
+            if (join != null)
+                return join;
+        }
+        ClassMapping sup = getJoinablePCSuperclassMapping();
+        if (sup != null) {
+            join = sup.getJoinable(col);
+            if (join != null)
+                return join;
+        }
+        return (Joinable) _joinables.get(col);
+    }
+
+    /**
+     * Add the given column-to-joinable mapping.
+     */
+    public void setJoinable(Column col, Joinable joinable) {
+        // don't let non-pk override pk
+        Joinable join = (Joinable) _joinables.get(col);
+        if (join == null || (join.getFieldIndex() != -1
+            && getField(join.getFieldIndex()).getPrimaryKeyIndex() == -1))
+            _joinables.put(col, joinable);
+    }
+
+    /**
+     * Return whether the columns of the given foreign key to this mapping
+     * can be used to construct an object id for this type. This is a
+     * relatively expensive operation; its results should be cached.
+     *
+     * @return {@link Boolean#TRUE} if the foreign key contains all oid
+     * columns, <code>null</code> if it contains only some columns,
+     * or {@link Boolean#FALSE} if it contains non-oid columns
+     */
+    public Boolean isForeignKeyObjectId(ForeignKey fk) {
+        // if this mapping's primary key can't construct an oid, then no way
+        // foreign key can
+        if (getIdentityType() == ID_UNKNOWN || !isPrimaryKeyObjectId(false))
+            return Boolean.FALSE;
+
+        // with datastore identity, it's all or nothing
+        Column[] cols = fk.getPrimaryKeyColumns();
+        if (getIdentityType() == ID_DATASTORE) {
+            if (cols.length != 1 || cols[0] != getPrimaryKeyColumns()[0])
+                return Boolean.FALSE;
+            return Boolean.TRUE;
+        }
+
+        // check the join mapping for each pk column to see if it links up to
+        // a primary key field
+        Joinable join;
+        for (int i = 0; i < cols.length; i++) {
+            join = assertJoinable(cols[i]);
+            if (join.getFieldIndex() != -1
+                && getField(join.getFieldIndex()).getPrimaryKeyIndex() == -1)
+                return Boolean.FALSE;
+        }
+
+        // if all primary key links, see whether we join to all pks
+        if (isPrimaryKeyObjectId(true)
+            && cols.length == getPrimaryKeyColumns().length)
+            return Boolean.TRUE;
+        return null;
+    }
+
+    ///////
+    // ORM
+    ///////
+
+    /**
+     * Raw mapping data.
+     */
+    public ClassMappingInfo getMappingInfo() {
+        return _info;
+    }
+
+    /**
+     * The strategy used to map this mapping.
+     */
+    public ClassStrategy 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(ClassStrategy strategy, Boolean adapt) {
+        // set strategy first so we can access it during mapping
+        ClassStrategy orig = _strategy;
+        _strategy = strategy;
+        if (strategy != null) {
+            try {
+                strategy.setClassMapping(this);
+                if (adapt != null)
+                    strategy.map(adapt.booleanValue());
+            } catch (RuntimeException re) {
+                // reset strategy
+                _strategy = orig;
+                throw re;
+            }
+        }
+    }
+
+    /**
+     * The mapping's primary table.
+     */
+    public Table getTable() {
+        return _table;
+    }
+
+    /**
+     * The mapping's primary table.
+     */
+    public void setTable(Table table) {
+        _table = table;
+    }
+
+    /**
+     * The columns this mapping uses to uniquely identify an object.
+     * These will typically be the primary key columns or the columns this
+     * class uses to link to its superclass table.
+     */
+    public Column[] getPrimaryKeyColumns() {
+        if (_cols.length == 0 && getIdentityType() == ID_APPLICATION
+            && isMapped()) {
+            FieldMapping[] pks = getPrimaryKeyFieldMappings();
+            Collection cols = new ArrayList(pks.length);
+            Column[] fieldCols;
+            for (int i = 0; i < pks.length; i++) {
+                fieldCols = pks[i].getColumns();
+                for (int j = 0; j < fieldCols.length; j++)
+                    cols.add(fieldCols[j]);
+            }
+            _cols = (Column[]) cols.toArray(new Column[cols.size()]);
+        }
+        return _cols;
+    }
+
+    /**
+     * The columns this mapping uses to uniquely identify an object.
+     * These will typically be the primary key columns or the columns this
+     * class uses to link to its superclass table.
+     */
+    public void setPrimaryKeyColumns(Column[] cols) {
+        if (cols == null)
+            cols = Schemas.EMPTY_COLUMNS;
+        _cols = cols;
+    }
+
+    /**
+     * I/O information on the key columns / join key.
+     */
+    public ColumnIO getColumnIO() {
+        return (_io == null) ? ColumnIO.UNRESTRICTED : _io;
+    }
+
+    /**
+     * I/O information on the key columns / join key.
+     */
+    public void setColumnIO(ColumnIO io) {
+        _io = io;
+    }
+
+    /**
+     * Foreign key linking the primary key columns to the superclass table,
+     * or null if none.
+     */
+    public ForeignKey getJoinForeignKey() {
+        return _fk;
+    }
+
+    /**
+     * Foreign key linking the primary key columns to the superclass table,
+     * or null if none.
+     */
+    public void setJoinForeignKey(ForeignKey fk) {
+        _fk = fk;
+    }
+
+    public void refSchemaComponents() {
+        if (getEmbeddingMetaData() == null) {
+            if (_table != null && _table.getPrimaryKey() != null)
+                _table.getPrimaryKey().ref();
+            if (_fk != null)
+                _fk.ref();
+            Column[] pks = getPrimaryKeyColumns();
+            for (int i = 0; i < pks.length; i++)
+                pks[i].ref();
+        } else {
+            FieldMapping[] fields = getFieldMappings();
+            for (int i = 0; i < fields.length; i++)
+                fields[i].refSchemaComponents();
+        }
+    }
+
+    /**
+     * Clear mapping information, including strategy.
+     */
+    public void clearMapping() {
+        _strategy = null;
+        _cols = Schemas.EMPTY_COLUMNS;
+        _fk = null;
+        _table = null;
+        _info.clear();
+        setResolve(MODE_MAPPING | MODE_MAPPING_INIT, false);
+    }
+
+    /**
+     * Update {@link MappingInfo} with our current mapping information.
+     */
+    public void syncMappingInfo() {
+        if (getEmbeddingMetaData() == null)
+            _info.syncWith(this);
+        else {
+            _info.clear();
+            FieldMapping[] fields = getFieldMappings();
+            for (int i = 0; i < fields.length; i++)
+                fields[i].syncMappingInfo();
+        }
+    }
+
+    //////////////////////
+    // MetaData interface
+    //////////////////////
+
+    protected void setDescribedType(Class type) {
+        super.setDescribedType(type);
+        // this method called from superclass constructor, so _info not yet
+        // initialized
+        if (_info != null)
+            _info.setClassName(type.getName());
+    }
+
+    /**
+     * The subclass fetch mode, as one of the eager constants in
+     * {@link JDBCFetchConfiguration}.
+     */
+    public int getSubclassFetchMode() {
+        if (_subclassMode == Integer.MAX_VALUE) {
+            if (getPCSuperclass() != null)
+                _subclassMode = getPCSuperclassMapping().
+                    getSubclassFetchMode();
+            else
+                _subclassMode = FetchConfiguration.DEFAULT;
+        }
+        return _subclassMode;
+    }
+
+    /**
+     * The subclass fetch mode, as one of the eager constants in
+     * {@link JDBCFetchConfiguration}.
+     */
+    public void setSubclassFetchMode(int mode) {
+        _subclassMode = mode;
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getRepository}.
+     */
+    public MappingRepository getMappingRepository() {
+        return (MappingRepository) getRepository();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getEmbeddingMetaData}
+     */
+    public ValueMapping getEmbeddingMapping() {
+        return (ValueMapping) getEmbeddingMetaData();
+    }
+
+    /**
+     * Returns true if this 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() {
+        if (!super.isMapped())
+            return false;
+        if (_strategy != null)
+            return _strategy != NoneClassStrategy.getInstance();
+        return !NoneClassStrategy.ALIAS.equals(_info.getStrategy());
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getPCSuperclassMetaData}.
+     */
+    public ClassMapping getPCSuperclassMapping() {
+        return (ClassMapping) getPCSuperclassMetaData();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getMappedPCSuperclassMetaData}.
+     */
+    public ClassMapping getMappedPCSuperclassMapping() {
+        return (ClassMapping) getMappedPCSuperclassMetaData();
+    }
+
+    /**
+     * Return the nearest mapped superclass that can join to this class.
+     */
+    public ClassMapping getJoinablePCSuperclassMapping() {
+        ClassMapping sup = getMappedPCSuperclassMapping();
+        if (sup == null)
+            return null;
+        if (_fk != null || _table == null || _table.equals(sup.getTable()))
+            return sup;
+        return null;
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getPCSubclassMetaDatas}.
+     */
+    public ClassMapping[] getPCSubclassMappings() {
+        return (ClassMapping[]) getPCSubclassMetaDatas();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getMappedPCSubclassMetaDatas}.
+     */
+    public ClassMapping[] getMappedPCSubclassMappings() {
+        return (ClassMapping[]) getMappedPCSubclassMetaDatas();
+    }
+
+    /**
+     * Return mapped subclasses that are reachable via joins.
+     */
+    public ClassMapping[] getJoinablePCSubclassMappings() {
+        ClassMapping[] subs = getMappedPCSubclassMappings(); // checks for new
+        if (_joinSubMaps == null) {
+            if (subs.length == 0)
+                _joinSubMaps = subs;
+            else {
+                List joinable = new ArrayList(subs.length);
+                for (int i = 0; i < subs.length; i++)
+                    if (isSubJoinable(subs[i]))
+                        joinable.add(subs[i]);
+                _joinSubMaps = (ClassMapping[]) joinable.toArray
+                    (new ClassMapping[joinable.size()]);
+            }
+        }
+        return _joinSubMaps;
+    }
+
+    /**
+     * Return whether we can reach the given subclass via joins.
+     */
+    private boolean isSubJoinable(ClassMapping sub) {
+        if (sub == null)
+            return false;
+        if (sub == this)
+            return true;
+        return isSubJoinable(sub.getJoinablePCSuperclassMapping());
+    }
+
+    /**
+     * Returns the closest-derived list of non-inter-joinable mapped types
+     * assignable to this type. May return this mapping.
+     */
+    public ClassMapping[] getIndependentAssignableMappings() {
+        ClassMapping[] subs = getMappedPCSubclassMappings(); // checks for new
+        if (_assignMaps == null) {
+            // remove unmapped subs
+            if (subs.length == 0) {
+                if (isMapped())
+                    _assignMaps = new ClassMapping[]{ this };
+                else
+                    _assignMaps = subs;
+            } else {
+                int size = (int) (subs.length * 1.33 + 2);
+                Set independent = ListOrderedSet.decorate(new HashSet(size),
+                    new ArrayList(subs.length + 1));
+                if (isMapped())
+                    independent.add(this);
+                independent.addAll(Arrays.asList(subs));
+
+                // remove all mappings that have a superclass mapping in the set
+                ClassMapping map, sup;
+                List clear = null;
+                for (Iterator itr = independent.iterator(); itr.hasNext();) {
+                    map = (ClassMapping) itr.next();
+                    sup = map.getJoinablePCSuperclassMapping();
+                    if (sup != null && independent.contains(sup)) {
+                        if (clear == null)
+                            clear = new ArrayList(independent.size() - 1);
+                        clear.add(map);
+                    }
+                }
+                if (clear != null)
+                    independent.removeAll(clear);
+
+                _assignMaps = (ClassMapping[]) independent.toArray
+                    (new ClassMapping[independent.size()]);
+            }
+        }
+        return _assignMaps;
+    }
+
+    /**
+     * Convenience method to perform cast from {@link ClassMetaData#getFields}.
+     */
+    public FieldMapping[] getFieldMappings() {
+        return (FieldMapping[]) getFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDeclaredFields}.
+     */
+    public FieldMapping[] getDeclaredFieldMappings() {
+        return (FieldMapping[]) getDeclaredFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getPrimaryKeyFields}.
+     */
+    public FieldMapping[] getPrimaryKeyFieldMappings() {
+        return (FieldMapping[]) getPrimaryKeyFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getVersionField}.
+     */
+    public FieldMapping getVersionFieldMapping() {
+        return (FieldMapping) getVersionField();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDefaultFetchGroupFields}.
+     */
+    public FieldMapping[] getDefaultFetchGroupFieldMappings() {
+        return (FieldMapping[]) getDefaultFetchGroupFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDefinedFields}.
+     */
+    public FieldMapping[] getDefinedFieldMappings() {
+        return (FieldMapping[]) getDefinedFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getFieldsInListingOrder}.
+     */
+    public FieldMapping[] getFieldMappingsInListingOrder() {
+        return (FieldMapping[]) getFieldsInListingOrder();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDefinedFieldsInListingOrder}.
+     */
+    public FieldMapping[] getDefinedFieldMappingsInListingOrder() {
+        return (FieldMapping[]) getDefinedFieldsInListingOrder();
+    }
+
+    /**
+     * Convenience method to perform cast from {@link ClassMetaData#getField}.
+     */
+    public FieldMapping getFieldMapping(int index) {
+        return (FieldMapping) getField(index);
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDeclaredField}.
+     */
+    public FieldMapping getDeclaredFieldMapping(int index) {
+        return (FieldMapping) getDeclaredField(index);
+    }
+
+    /**
+     * Convenience method to perform cast from {@link ClassMetaData#getField}.
+     */
+    public FieldMapping getFieldMapping(String name) {
+        return (FieldMapping) getField(name);
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDeclaredField}.
+     */
+    public FieldMapping getDeclaredFieldMapping(String name) {
+        return (FieldMapping) getDeclaredField(name);
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#getDeclaredUnmanagedFields}.
+     */
+    public FieldMapping[] getDeclaredUnmanagedFieldMappings() {
+        return (FieldMapping[]) getDeclaredUnmanagedFields();
+    }
+
+    /**
+     * Convenience method to perform cast from
+     * {@link ClassMetaData#addDeclaredField}.
+     */
+    public FieldMapping addDeclaredFieldMapping(String name, Class type) {
+        return (FieldMapping) addDeclaredField(name, type);
+    }
+
+    protected void resolveMapping(boolean runtime) {
+        super.resolveMapping(runtime);
+
+        // map class strategy; it may already be mapped by the repository before
+        // the resolve process begins
+        MappingRepository repos = getMappingRepository();
+        if (_strategy == null)
+            repos.getStrategyInstaller().installStrategy(this);
+        Log log = getRepository().getLog();
+        if (log.isTraceEnabled())
+            log.trace(_loc.get("strategy", this, _strategy.getAlias()));
+
+        // make sure unmapped superclass fields are defined if we're mapped;
+        // also may have been done by repository already
+        defineSuperclassFields(getJoinablePCSuperclassMapping() == null);
+
+        // resolve everything that doesn't rely on any relations to avoid
+        // recursion, then resolve all fields
+        resolveNonRelationMappings();
+        FieldMapping[] fms = getFieldMappings();
+        for (int i = 0; i < fms.length; i++)
+            if (fms[i].getDefiningMetaData() == this)
+                fms[i].resolve(MODE_MAPPING);
+        fms = getDeclaredUnmanagedFieldMappings();
+        for (int i = 0; i < fms.length; i++)
+            fms[i].resolve(MODE_MAPPING);
+
+        // mark mapped columns
+        if (_cols != null) {
+            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);
+            }
+        }
+    }
+
+    /**
+     * Resolve non-relation field mappings so that when we do relation
+     * mappings they can rely on them for joins.
+     */
+    void resolveNonRelationMappings() {
+        // make sure primary key fields are resolved first because other
+        // fields might rely on them
+        FieldMapping[] fms = getPrimaryKeyFieldMappings();
+        for (int i = 0; i < fms.length; i++)
+            fms[i].resolve(MODE_MAPPING);
+
+        // resolve defined fields that are safe; that don't rely on other types
+        // also being resolved.  don't use getDefinedFields b/c it relies on
+        // whether fields are mapped, which isn't known yet
+        fms = getFieldMappings();
+        for (int i = 0; i < fms.length; i++)
+            if (fms[i].getDefiningMetaData() == this
+                && !fms[i].isTypePC() && !fms[i].getKey().isTypePC()
+                && !fms[i].getElement().isTypePC())
+                fms[i].resolve(MODE_MAPPING);
+
+        _discrim.resolve(MODE_MAPPING);
+        _version.resolve(MODE_MAPPING);
+    }
+
+    protected void initializeMapping() {
+        super.initializeMapping();
+
+        FieldMapping[] fields = getDefinedFieldMappings();
+        for (int i = 0; i < fields.length; i++)
+            fields[i].resolve(MODE_MAPPING_INIT);
+        _discrim.resolve(MODE_MAPPING_INIT);
+        _version.resolve(MODE_MAPPING_INIT);
+        _strategy.initialize();
+    }
+
+    protected void clearDefinedFieldCache() {
+        // just make this method available to other classes in this package
+        super.clearDefinedFieldCache();
+    }
+
+    protected void clearSubclassCache() {
+        super.clearSubclassCache();
+        _joinSubMaps = null;
+        _assignMaps = null;
+    }
+
+    public void copy(ClassMetaData cls) {
+        super.copy(cls);
+        if (_subclassMode == Integer.MAX_VALUE)
+            _subclassMode = ((ClassMapping) cls).getSubclassFetchMode();
+    }
+
+    protected boolean validateDataStoreExtensionPrefix(String prefix) {
+        return "jdbc-".equals(prefix);
+    }
+
+    ////////////////////////////////
+    // ClassStrategy 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 setClassMapping(ClassMapping owner) {
+        assertStrategy().setClassMapping(owner);
+    }
+
+    public boolean isPrimaryKeyObjectId(boolean hasAll) {
+        return assertStrategy().isPrimaryKeyObjectId(hasAll);
+    }
+
+    public Joins joinSuperclass(Joins joins, boolean toThis) {
+        return assertStrategy().joinSuperclass(joins, toThis);
+    }
+
+    public boolean supportsEagerSelect(Select sel, OpenJPAStateManager sm,
+        JDBCStore store, ClassMapping base, JDBCFetchConfiguration fetch) {
+        return assertStrategy().supportsEagerSelect(sel, sm, store, base,
+            fetch);
+    }
+
+    public ResultObjectProvider customLoad(JDBCStore store, boolean subclasses,
+        JDBCFetchConfiguration fetch, long startIdx, long endIdx)
+        throws SQLException {
+        return assertStrategy().customLoad(store, subclasses, fetch,
+            startIdx, endIdx);
+    }
+
+    public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
+        PCState state, JDBCFetchConfiguration fetch)
+        throws SQLException, ClassNotFoundException {
+        return assertStrategy().customLoad(sm, store, state, fetch);
+    }
+
+    public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchConfiguration fetch, Result result)
+        throws SQLException {
+        return assertStrategy().customLoad(sm, store, fetch, result);
+    }
+
+    private ClassStrategy assertStrategy() {
+        if (_strategy == null)
+            throw new InternalException();
+        return _strategy;
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassMappingInfo.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,341 @@
+/*
+ * 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.io.File;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ForeignKey;
+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.lib.meta.SourceTracker;
+import org.apache.openjpa.lib.xml.Commentable;
+
+/**
+ * Information about the mapping from a class 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 ClassMappingInfo
+    extends MappingInfo
+    implements SourceTracker, Commentable {
+
+    private String _className = Object.class.getName();
+    private String _tableName = null;
+    private boolean _joined = false;
+    private Map _seconds = null;
+    private String _subStrat = null;
+    private File _file = null;
+    private int _srcType = SRC_OTHER;
+    private String[] _comments = null;
+
+    /**
+     * The described class name.
+     */
+    public String getClassName() {
+        return _className;
+    }
+
+    /**
+     * The described class name.
+     */
+    public void setClassName(String name) {
+        _className = name;
+    }
+
+    /**
+     * The default strategy for subclasses in this hierarchy.
+     */
+    public String getHierarchyStrategy() {
+        return _subStrat;
+    }
+
+    /**
+     * The default strategy for subclasses in this hierarchy.
+     */
+    public void setHierarchyStrategy(String strategy) {
+        _subStrat = strategy;
+    }
+
+    /**
+     * The given table name.
+     */
+    public String getTableName() {
+        return _tableName;
+    }
+
+    /**
+     * The given table name.
+     */
+    public void setTableName(String table) {
+        _tableName = table;
+    }
+
+    /**
+     * Whether there is a join to the superclass table.
+     */
+    public boolean isJoinedSubclass() {
+        return _joined;
+    }
+
+    /**
+     * Whether there is a join to the superclass table.
+     */
+    public void setJoinedSubclass(boolean joined) {
+        _joined = joined;
+    }
+
+    /**
+     * Return the class-level joined tables.
+     */
+    public String[] getSecondaryTableNames() {
+        if (_seconds == null)
+            return new String[0];
+        return (String[]) _seconds.keySet().toArray(new String[]{ });
+    }
+
+    /**
+     * We allow fields to reference class-level joins using just the table
+     * name, whereas the class join might have schema, etc information.
+     * This method returns the name of the given table as listed in a
+     * class-level join, or the given name if no join exists.
+     */
+    public String getSecondaryTableName(String tableName) {
+        // if no secondary table joins, bad table name, exact match,
+        // or an already-qualified table name, nothing to do
+        if (_seconds == null || tableName == null
+            || _seconds.containsKey(tableName)
+            || tableName.indexOf('.') != -1)
+            return tableName;
+
+        // decide which class-level join table is best match
+        String best = tableName;
+        int pts = 0;
+        String fullJoin;
+        String join;
+        int idx;
+        for (Iterator itr = _seconds.keySet().iterator(); itr.hasNext();) {
+            // award a caseless match without schema 2 points
+            fullJoin = (String) itr.next();
+            idx = fullJoin.lastIndexOf('.');
+            if (idx == -1 && pts < 2 && fullJoin.equalsIgnoreCase(tableName)) {
+                best = fullJoin;
+                pts = 2;
+            } else if (idx == -1)
+                continue;
+
+            // immediately return an exact match with schema
+            join = fullJoin.substring(idx + 1);
+            if (join.equals(tableName))
+                return join;
+
+            // caseless match with schema worth 1 point
+            if (pts < 1 && join.equalsIgnoreCase(tableName)) {
+                best = fullJoin;
+                pts = 1;
+            }
+        }
+        return best;
+    }
+
+    /**
+     * Return any columns defined for the given class level join, or empty
+     * list if none.
+     */
+    public List getSecondaryTableJoinColumns(String tableName) {
+        if (_seconds == null || tableName == null)
+            return Collections.EMPTY_LIST;
+
+        // get the columns for the join with the best match for table name
+        List cols = (List) _seconds.get(getSecondaryTableName(tableName));
+        if (cols == null) {
+            // possible that given table has extra info the join table
+            // doesn't have; strip it
+            int idx = tableName.lastIndexOf('.');
+            if (idx != -1) {
+                tableName = tableName.substring(idx + 1);
+                cols = (List) _seconds.get(getSecondaryTableName(tableName));
+            }
+        }
+        return (cols == null) ? Collections.EMPTY_LIST : cols;
+    }
+
+    /**
+     * Declare the given class-level join.
+     */
+    public void setSecondaryTableJoinColumns(String tableName, List cols) {
+        if (cols == null)
+            cols = Collections.EMPTY_LIST;
+        if (_seconds == null)
+            _seconds = new HashMap();
+        _seconds.put(tableName, cols);
+    }
+
+    /**
+     * Return the table for the given class.
+     */
+    public Table getTable(final ClassMapping cls, boolean adapt) {
+        return createTable(cls, new TableDefaults() {
+            public String get(Schema schema) {
+                // delay this so that we don't do schema reflection for unique
+                // table name unless necessary
+                return cls.getMappingRepository().getMappingDefaults().
+                    getTableName(cls, schema);
+            }
+        }, null, _tableName, adapt);
+    }
+
+    /**
+     * Return the datastore identity columns for the given class, based on the
+     * given templates.
+     */
+    public Column[] getDataStoreIdColumns(ClassMapping cls, Column[] tmplates,
+        Table table, boolean adapt) {
+        cls.getMappingRepository().getMappingDefaults().
+            populateDataStoreIdColumns(cls, table, tmplates);
+        return createColumns(cls, "datastoreid", tmplates, table, adapt);
+    }
+
+    /**
+     * Return the join from this class to its superclass. The table for
+     * this class must be set.
+     */
+    public ForeignKey getSuperclassJoin(final ClassMapping cls, Table table,
+        boolean adapt) {
+        ClassMapping sup = cls.getJoinablePCSuperclassMapping();
+        if (sup == null)
+            return null;
+
+        ForeignKeyDefaults def = new ForeignKeyDefaults() {
+            public ForeignKey get(Table local, Table foreign, boolean inverse) {
+                return cls.getMappingRepository().getMappingDefaults().
+                    getJoinForeignKey(cls, local, foreign);
+            }
+
+            public void populate(Table local, Table foreign, Column col,
+                Object target, boolean inverse, int pos, int cols) {
+                cls.getMappingRepository().getMappingDefaults().
+                    populateJoinColumn(cls, local, foreign, col, target,
+                        pos, cols);
+            }
+        };
+        return createForeignKey(cls, "superclass", getColumns(), def, table,
+            cls, sup, false, adapt);
+    }
+
+    /**
+     * Synchronize internal information with the mapping data for the given
+     * class.
+     */
+    public void syncWith(ClassMapping cls) {
+        clear(false);
+
+        ClassMapping sup = cls.getMappedPCSuperclassMapping();
+        if (cls.getTable() != null && (sup == null
+            || sup.getTable() != cls.getTable()))
+            _tableName = cls.getMappingRepository().getDBDictionary().
+                getFullName(cls.getTable(), true);
+
+        // set io before syncing cols
+        setColumnIO(cls.getColumnIO());
+        if (cls.getJoinForeignKey() != null && sup != null
+            && sup.getTable() != null)
+            syncForeignKey(cls, cls.getJoinForeignKey(), cls.getTable(),
+                sup.getTable());
+        else if (cls.getIdentityType() == ClassMapping.ID_DATASTORE)
+            syncColumns(cls, cls.getPrimaryKeyColumns(), false);
+
+        // record inheritance strategy if class does not use default strategy
+        // for base classes, and for all subclasses so we can be sure subsequent
+        // mapping runs don't think subclass is unmapped
+        String strat = (cls.getStrategy() == null) ? null
+            : cls.getStrategy().getAlias();
+        if (strat != null && (cls.getPCSuperclass() != null
+            || !FullClassStrategy.ALIAS.equals(strat)))
+            setStrategy(strat);
+    }
+
+    public boolean hasSchemaComponents() {
+        return super.hasSchemaComponents() || _tableName != null;
+    }
+
+    protected void clear(boolean canFlags) {
+        super.clear(canFlags);
+        _tableName = null;
+    }
+
+    public void copy(MappingInfo info) {
+        super.copy(info);
+        if (!(info instanceof ClassMappingInfo))
+            return;
+
+        ClassMappingInfo cinfo = (ClassMappingInfo) info;
+        if (_tableName == null)
+            _tableName = cinfo.getTableName();
+        if (_subStrat == null)
+            _subStrat = cinfo.getHierarchyStrategy();
+        if (cinfo._seconds != null) {
+            if (_seconds == null)
+                _seconds = new HashMap();
+            Object key;
+            for (Iterator itr = cinfo._seconds.keySet().iterator();
+                itr.hasNext();) {
+                key = itr.next();
+                if (!_seconds.containsKey(key))
+                    _seconds.put(key, cinfo._seconds.get(key));
+            }
+        }
+    }
+
+    public File getSourceFile() {
+        return _file;
+    }
+
+    public Object getSourceScope() {
+        return null;
+    }
+
+    public int getSourceType() {
+        return _srcType;
+    }
+
+    public void setSource(File file, int srcType) {
+        _file = file;
+        _srcType = srcType;
+    }
+
+    public String getResourceName() {
+        return _className;
+    }
+
+    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/ClassMappingInfo.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassStrategy.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassStrategy.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassStrategy.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ClassStrategy.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,112 @@
+/*
+ * 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.JDBCStore;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.jdbc.sql.Select;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.kernel.PCState;
+import org.apache.openjpa.lib.rop.ResultObjectProvider;
+
+/**
+ * Mapping from a class to a relational schema.
+ *
+ * @author Abe White
+ * @since 4.0
+ */
+public interface ClassStrategy
+    extends Strategy {
+
+    /**
+     * Set the class mapping using this strategy. This will be called before
+     * use.
+     */
+    public void setClassMapping(ClassMapping owner);
+
+    /**
+     * Return true if the this class' primary key columns correspond to the
+     * base class' primary key columns used to construct oid values. Base
+     * classes always return true. Classes that join to the base class table,
+     * though, may not always join using the same columns the base class
+     * uses for oid values, or may not use all the columns. When performing a
+     * select, we will join down to the most-derived class that is identified
+     * by oid values. We cannot use non-primary key field values for joining
+     * during selects, because the field values to join on might be the ones
+     * we're trying to select! Similarly, we can only reconstruct oid values
+     * for selected objects using classes whose primary keys store oid values.
+     *
+     * @param hasAll if true, there must be a primary key column for every
+     * base class primary key column; if false the primary key
+     * must only match a subset of the base class primary key columns
+     */
+    public boolean isPrimaryKeyObjectId(boolean hasAll);
+
+    /**
+     * Join the mapping and its superclass.
+     *
+     * @param toThis if false, inner join to the superclass table; if
+     * true, outer join from the superclass table to this table
+     */
+    public Joins joinSuperclass(Joins joins, boolean toThis);
+
+    /**
+     * Return true if this strategy can perform the given select from
+     * the given <code>base</code> mapping.
+     * The given state manager may be null if selecting multiple instances.
+     */
+    public boolean supportsEagerSelect(Select sel, OpenJPAStateManager sm,
+        JDBCStore store, ClassMapping base, JDBCFetchConfiguration fetch);
+
+    /**
+     * Implement this method to customize obtaining a result containing all
+     * instances of this class. Return null for standard loading.
+     */
+    public ResultObjectProvider customLoad(JDBCStore store, boolean subclasses,
+        JDBCFetchConfiguration fetch, long startIdx, long endIdx)
+        throws SQLException;
+
+    /**
+     * Implement this method to load the state of a given object, without
+     * a previous {@link Result}. Return true if this method handles the
+     * load. If the object does not exist in the data store, simply take no
+     * action on it (but still return true). Return false to use default
+     * loading.
+     *
+     * @param state if non-null, then you must initialize the state
+     * and persistent object of the given state manager
+     * (after determining the actual class of the object
+     * from the database, if there are possible persistent
+     * subclasses); initialization looks like this: <code>
+     * sm.initialize (pcClass, state)</code>
+     */
+    public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
+        PCState state, JDBCFetchConfiguration fetch)
+        throws SQLException, ClassNotFoundException;
+
+    /**
+     * Implement this method to customize loading from a {@link Result}
+     * into an instance. Return true if this mapping handles the
+     * load; false if normal loading should procede after calling this method.
+     */
+    public boolean customLoad(OpenJPAStateManager sm, JDBCStore store,
+        JDBCFetchConfiguration fetch, Result result)
+        throws SQLException;
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/DelegatingJoinable.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,125 @@
+/*
+ * 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.ForeignKey;
+import org.apache.openjpa.jdbc.sql.Joins;
+import org.apache.openjpa.jdbc.sql.Result;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.MetaDataException;
+
+/**
+ * Delegates to another {@link Joinable} after doing column
+ * translation. Useful for joins that are not managed by any fields on
+ * the joined-from side. For example, a vertical class mapping manages
+ * foreign key columns linking to the superclass table. It needs to use
+ * the joinables of the superclass to actually extract the column values
+ * from field values and so forth, but in order for other mappings to join
+ * to its foreign key columns it needs joinables of its own. So it creates
+ * delegating joinables.
+ *
+ * @author Abe White
+ */
+public class DelegatingJoinable
+    implements Joinable {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (DelegatingJoinable.class);
+
+    private final Joinable _join;
+    private final ForeignKey _fk;
+    private final Column[] _cols;
+
+    /**
+     * Constructor.
+     *
+     * @param join the mapping to delegate to
+     * @param fk the foreign key to use to translate any given columns
+     * to the given delegate's columns
+     */
+    public DelegatingJoinable(Joinable join, ForeignKey fk) {
+        _join = join;
+        _fk = fk;
+
+        Column[] pks = join.getColumns();
+        _cols = new Column[pks.length];
+        for (int i = 0; i < pks.length; i++) {
+            _cols[i] = fk.getColumn(pks[i]);
+            if (_cols[i] == null)
+                throw new MetaDataException(_loc.get("incomplete-join",
+                    pks[i].getFullName()));
+        }
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param join the mapping to delegate to
+     * @param cols translated columns
+     */
+    public DelegatingJoinable(Joinable join, Column[] cols) {
+        _join = join;
+        _fk = null;
+        _cols = cols;
+        if (cols.length != join.getColumns().length)
+            throw new MetaDataException(_loc.get("bad-remap",
+                join.getColumns()[0].getFullName()));
+    }
+
+    public int getFieldIndex() {
+        return _join.getFieldIndex();
+    }
+
+    public Object getPrimaryKeyValue(Result res, Column[] cols, ForeignKey fk,
+        Joins joins)
+        throws SQLException {
+        return _join.getPrimaryKeyValue(res, cols, fk, joins);
+    }
+
+    public Column[] getColumns() {
+        return _cols;
+    }
+
+    public Object getJoinValue(Object val, Column col, JDBCStore store) {
+        return _join.getJoinValue(val, translate(col), store);
+    }
+
+    public Object getJoinValue(OpenJPAStateManager sm, Column col,
+        JDBCStore store) {
+        return _join.getJoinValue(sm, translate(col), store);
+    }
+
+    public void setAutoAssignedValue(OpenJPAStateManager sm, JDBCStore store,
+        Column col, Object autogen) {
+        _join.setAutoAssignedValue(sm, store, translate(col), autogen);
+    }
+
+    private Column translate(Column col) {
+        if (_fk != null)
+            return _fk.getPrimaryKeyColumn(col);
+
+        Column[] cols = _join.getColumns();
+        for (int i = 0; i < cols.length; i++)
+            if (col == cols[i])
+                return _cols[i];
+        return null;
+    }
+}

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