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 [26/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/schema/LazySchemaFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LazySchemaFactory.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LazySchemaFactory.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LazySchemaFactory.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,190 @@
+/*
+ * 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.schema;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.SQLExceptions;
+import org.apache.openjpa.lib.conf.Configurable;
+import org.apache.openjpa.lib.conf.Configuration;
+
+/**
+ * Factory that uses database metadata to construct the system schema.
+ * The lazy schema factory only loads table data as it is requested. It
+ * does not properly support operations that require knowledge of the entire
+ * schema.
+ *
+ * @author Abe White
+ */
+public class LazySchemaFactory
+    extends SchemaGroup
+    implements SchemaFactory, Configurable {
+
+    private JDBCConfiguration _conf = null;
+    private SchemaGenerator _gen = null;
+    private Connection _conn = null;
+    private DatabaseMetaData _meta = null;
+    private boolean _indexes = false;
+    private boolean _pks = false;
+    private boolean _fks = false;
+
+    public boolean getPrimaryKeys() {
+        return _pks;
+    }
+
+    public void setPrimaryKeys(boolean pks) {
+        _pks = pks;
+    }
+
+    public boolean getForeignKeys() {
+        return _fks;
+    }
+
+    public void setForeignKeys(boolean fks) {
+        _fks = fks;
+    }
+
+    public boolean getIndexes() {
+        return _indexes;
+    }
+
+    public void setIndexes(boolean idx) {
+        _indexes = idx;
+    }
+
+    public SchemaGroup readSchema() {
+        return this;
+    }
+
+    public void storeSchema(SchemaGroup schema) {
+        // nothing to do
+    }
+
+    public Table findTable(String name) {
+        if (name == null)
+            return null;
+
+        Table table = super.findTable(name);
+        if (table != null)
+            return table;
+
+        generateSchemaObject(name, true);
+        return super.findTable(name);
+    }
+
+    public Sequence findSequence(String name) {
+        if (name == null)
+            return null;
+
+        Sequence seq = super.findSequence(name);
+        if (seq != null)
+            return seq;
+
+        generateSchemaObject(name, false);
+        return super.findSequence(name);
+    }
+
+    /**
+     * Generate the table or sequence with the given name.
+     */
+    private void generateSchemaObject(String name, boolean isTable) {
+        // if full name, split
+        String schemaName = null;
+        String objectName = name;
+
+        // look for the standard schema separator...
+        int dotIdx = name.indexOf('.');
+        // ... or the dictionary schema separator
+        if (dotIdx == -1) {
+            String sep = _conf.getDBDictionaryInstance().catalogSeparator;
+            if (!".".equals(sep))
+                dotIdx = name.indexOf(sep);
+        }
+
+        if (dotIdx != -1) {
+            schemaName = name.substring(0, dotIdx);
+            objectName = name.substring(dotIdx + 1);
+        }
+
+        // we share a single connection across all schemas, so synch
+        // on the schema group
+        synchronized (this) {
+            boolean close = false;
+            try {
+                // use the existing connection if possible; this method
+                // might be reentrant if generating the foreign keys for
+                // this table (see below) requires loading additional
+                // tables; in that case we don't want to spawn additional
+                // connections
+                if (_conn == null) {
+                    _conn = _conf.getDataSource2(null).getConnection();
+                    close = true;
+                    _meta = _conn.getMetaData();
+                }
+
+                if (isTable) {
+                    // generate the table from database metadata
+                    _gen.generateTables(schemaName, objectName, _conn, _meta);
+                    Table table = super.findTable(name);
+
+                    if (table != null) {
+                        if (_pks)
+                            _gen.generatePrimaryKeys(table.getSchemaName(),
+                                table.getName(), _conn, _meta);
+                        if (_indexes)
+                            _gen.generateIndexes(table.getSchemaName(),
+                                table.getName(), _conn, _meta);
+
+                        // generate foreign keys from the table; this might
+                        // end up re-calling this getTable method if the foreign
+                        // key links to a table that hasn't been loaded yet
+                        if (_fks)
+                            _gen.generateForeignKeys(table.getSchemaName(),
+                                table.getName(), _conn, _meta);
+                    }
+                } else
+                    _gen.generateSequences(schemaName, objectName, _conn,
+                        _meta);
+            } catch (SQLException se) {
+                throw SQLExceptions.getStore(se,
+                    _conf.getDBDictionaryInstance());
+            } finally {
+                if (close) {
+                    try {
+                        _conn.close();
+                    } catch (SQLException se) {
+                    }
+                    _conn = null;
+                }
+            }
+        }
+    }
+
+    public void setConfiguration(Configuration conf) {
+        _conf = (JDBCConfiguration) conf;
+        _gen = new SchemaGenerator(_conf);
+        _gen.setSchemaGroup(this);
+    }
+
+    public void startConfiguration() {
+    }
+
+    public void endConfiguration() {
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/LocalConstraint.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,184 @@
+/*
+ * 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.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.InvalidStateException;
+
+/**
+ * Constraint over local table columns, as opposed to a foreign key which
+ * spans tables. Column APIs can represent a full constraint or a partial
+ * constraint, aligning with {@link java.sql.DatabaseMetaData}.
+ *
+ * @author Abe White
+ */
+public abstract class LocalConstraint
+    extends Constraint {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (LocalConstraint.class);
+
+    private List _colList = null;
+    private Column[] _cols = null;
+
+    /**
+     * Default constructor.
+     */
+    public LocalConstraint() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name the name of the constraint, if any
+     * @param table the table of the constraint
+     */
+    public LocalConstraint(String name, Table table) {
+        super(name, table);
+    }
+
+    /**
+     * Called when the constraint is removed from its table.
+     */
+    void remove() {
+        // remove all columns
+        setColumns(null);
+        super.remove();
+    }
+
+    /**
+     * Return all the columns the constraint spans.
+     */
+    public Column[] getColumns() {
+        if (_cols == null)
+            _cols = (_colList == null) ? Schemas.EMPTY_COLUMNS
+                : (Column[]) _colList.toArray(new Column[_colList.size()]);
+        return _cols;
+    }
+
+    /**
+     * Set the columns the constraint spans.
+     */
+    public void setColumns(Column[] cols) {
+        Column[] cur = getColumns();
+        for (int i = 0; i < cur.length; i++)
+            removeColumn(cur[i]);
+
+        if (cols != null)
+            for (int i = 0; i < cols.length; i++)
+                addColumn(cols[i]);
+    }
+
+    /**
+     * Add a column to the constraint.
+     */
+    public void addColumn(Column col) {
+        if (col == null || !ObjectUtils.equals(col.getTable(), getTable()))
+            throw new InvalidStateException(_loc.get("table-mismatch",
+                col == null ? null : col.getTable(),
+                col == null ? null : getTable()));
+
+        if (_colList == null)
+            _colList = new ArrayList(3);
+        else if (_colList.contains(col))
+            return;
+
+        _colList.add(col);
+        _cols = null;
+    }
+
+    /**
+     * Remove a column from the constraint.
+     *
+     * @return true if the column was removed, false if not part of the
+     * primary key
+     */
+    public boolean removeColumn(Column col) {
+        if (col == null || _colList == null)
+            return false;
+        if (_colList.remove(col)) {
+            _cols = null;
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Return true if the pk includes the given column.
+     */
+    public boolean containsColumn(Column col) {
+        if (col == null || _colList == null)
+            return false;
+        return _colList.contains(col);
+    }
+
+    /**
+     * Ref all columns in this constraint.
+     */
+    public void refColumns() {
+        Column[] cols = getColumns();
+        for (int i = 0; i < cols.length; i++)
+            cols[i].ref();
+    }
+
+    /**
+     * Deref all columns in this constraint.
+     */
+    public void derefColumns() {
+        Column[] cols = getColumns();
+        for (int i = 0; i < cols.length; i++)
+            cols[i].deref();
+    }
+
+    /**
+     * Return true if the given columns match the columns of this constraint.
+     */
+    public boolean columnsMatch(Column[] ocols) {
+        Column[] cols = getColumns();
+        if (cols.length != ocols.length)
+            return false;
+        for (int i = 0; i < ocols.length; i++)
+            if (!hasColumn(cols, ocols[i]))
+                return false;
+        return true;
+    }
+
+    /**
+     * Return whether the given column exists in the array.
+     */
+    private static boolean hasColumn(Column[] cols, Column col) {
+        for (int i = 0; i < cols.length; i++)
+            if (cols[i].getFullName().equalsIgnoreCase(col.getFullName()))
+                return true;
+        return false;
+    }
+
+    /**
+     * Return true if the columns of this constraint matches that of
+     * the given one. The constraints are not compared on name.
+     */
+    protected boolean equalsLocalConstraint(LocalConstraint lc) {
+        if (lc == this)
+            return true;
+        if (lc == null)
+            return false;
+        return columnsMatch(lc.getColumns());
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/NameSet.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/NameSet.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/NameSet.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/NameSet.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,73 @@
+/*
+ * 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.schema;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.openjpa.lib.util.Localizer;
+
+/**
+ * Name sets track what names have been taken, ignoring case.
+ * {@link SchemaGroup}s implement this interface for tables, indexes, and
+ * constraints; {@link Table}s implement it for their columns.
+ *
+ * @author Abe White
+ */
+public class NameSet {
+
+    private static final Localizer _loc = Localizer.forPackage(NameSet.class);
+
+    private Set _names = null;
+
+    /**
+     * Return true if the given name is in use already.
+     */
+    public boolean isNameTaken(String name) {
+        if (name == null)
+            return true;
+        return _names != null && _names.contains(name.toUpperCase());
+    }
+
+    /**
+     * Attempt to add the given name to the set.
+     *
+     * @param name the name to add
+     * @param validate if true, null or empty names will not be accepted
+     */
+    protected void addName(String name, boolean validate) {
+        if (name == null || name.length() == 0) {
+            if (validate)
+                throw new IllegalArgumentException(_loc.get("bad-name", name));
+            return;
+        }
+
+        // unfortunately, we can't check for duplicate names, because different
+        // DBs use different namespaces for components, and it would be
+        // difficult to find a scheme that fits all and is still useful
+        if (_names == null)
+            _names = new HashSet();
+        _names.add(name.toUpperCase());
+    }
+
+    /**
+     * Remove the given name from the table.
+     */
+    protected void removeName(String name) {
+        if (name != null && _names != null)
+            _names.remove(name.toUpperCase());
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/PrimaryKey.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/PrimaryKey.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/PrimaryKey.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/PrimaryKey.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.schema;
+
+/**
+ * Represents a table primary key. It can also represent a partial key,
+ * aligning with the key information available from
+ * {@link java.sql.DatabaseMetaData}.
+ *
+ * @author Abe White
+ */
+public class PrimaryKey
+    extends LocalConstraint {
+
+    private boolean _logical = false;
+
+    /**
+     * Default constructor.
+     */
+    public PrimaryKey() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name the name of the primary key, if any
+     * @param table the table of the primary key
+     */
+    public PrimaryKey(String name, Table table) {
+        super(name, table);
+    }
+
+    public boolean isLogical() {
+        return _logical;
+    }
+
+    public void setLogical(boolean logical) {
+        _logical = logical;
+    }
+
+    void remove() {
+        // check all foreign keys in the schema group, removing ones that
+        // reference this primary key
+        Table table = getTable();
+        if (table != null && table.getSchema() != null
+            && table.getSchema().getSchemaGroup() != null) {
+            ForeignKey[] fks = table.getSchema().getSchemaGroup().
+                findExportedForeignKeys(this);
+            for (int i = 0; i < fks.length; i++)
+                fks[i].getTable().removeForeignKey(fks[i]);
+        }
+        super.remove();
+    }
+
+    public void addColumn(Column col) {
+        super.addColumn(col);
+        col.setPrimaryKey(true);
+        if (!_logical)
+            col.setNotNull(true);
+    }
+
+    /**
+     * Return true if the structure of this primary key matches that of
+     * the given one (same table, same columns).
+     */
+    public boolean equalsPrimaryKey(PrimaryKey pk) {
+        return equalsLocalConstraint(pk);
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ReferenceCounter.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ReferenceCounter.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ReferenceCounter.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/ReferenceCounter.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,39 @@
+/*
+ * 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.schema;
+
+/**
+ * Some schema components count references so that unused components
+ * can be detected.
+ *
+ * @author Abe White
+ */
+class ReferenceCounter {
+
+    private int _count = 0;
+
+    public int getRefCount() {
+        return _count;
+    }
+
+    public void ref() {
+        _count++;
+    }
+
+    public void deref() {
+        _count--;
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Schema.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Schema.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Schema.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/Schema.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,259 @@
+/*
+ * 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.schema;
+
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * Represents a database schema.
+ *
+ * @author Abe White
+ */
+public class Schema
+    implements Comparable {
+
+    private String _name = null;
+    private SchemaGroup _group = null;
+    private Map _tableMap = null;
+    private Map _seqMap = null;
+
+    // cache
+    private Table[] _tables = null;
+    private Sequence[] _seqs = null;
+
+    /**
+     * Default constructor.
+     */
+    public Schema() {
+    }
+
+    /**
+     * Constructor.
+     *
+     * @param name the schema name, if any
+     * @param group the schema's owning group
+     */
+    public Schema(String name, SchemaGroup group) {
+        setName(name);
+        _group = group;
+    }
+
+    /**
+     * Called when the schema is removed from its group. Invalidates the
+     * schema and removes all its member tables.
+     */
+    void remove() {
+        Table[] tabs = getTables();
+        for (int i = 0; i < tabs.length; i++)
+            removeTable(tabs[i]);
+        Sequence[] seqs = getSequences();
+        for (int i = 0; i < seqs.length; i++)
+            removeSequence(seqs[i]);
+        _group = null;
+    }
+
+    /**
+     * Return the schema's group.
+     */
+    public SchemaGroup getSchemaGroup() {
+        return _group;
+    }
+
+    /**
+     * Return the name of the schema, or null if none.
+     */
+    public String getName() {
+        return _name;
+    }
+
+    /**
+     * Set the name of the schema. This method can only be used for schemas
+     * not attached to a group.
+     */
+    public void setName(String name) {
+        if (getSchemaGroup() != null)
+            throw new IllegalStateException();
+        if (name != null && name.length() == 0)
+            name = null;
+        _name = name;
+    }
+
+    /**
+     * Return the schema's tables.
+     */
+    public Table[] getTables() {
+        if (_tables == null)
+            _tables = (_tableMap == null) ? new Table[0] : (Table[])
+                _tableMap.values().toArray(new Table[_tableMap.size()]);
+        return _tables;
+    }
+
+    /**
+     * Return the table with the given name, or null if none.
+     */
+    public Table getTable(String name) {
+        if (name == null || _tableMap == null)
+            return null;
+        return (Table) _tableMap.get(name.toUpperCase());
+    }
+
+    /**
+     * Add a table to the schema.
+     */
+    public Table addTable(String name) {
+        SchemaGroup group = getSchemaGroup();
+        Table tab;
+        if (group != null) {
+            group.addName(name, true);
+            tab = group.newTable(name, this);
+        } else
+            tab = new Table(name, this);
+        if (_tableMap == null)
+            _tableMap = new TreeMap();
+        _tableMap.put(name.toUpperCase(), tab);
+        _tables = null;
+        return tab;
+    }
+
+    /**
+     * Remove the given table from the schema.
+     *
+     * @return true if the table was removed, false if not in the schema
+     */
+    public boolean removeTable(Table tab) {
+        if (tab == null || _tableMap == null)
+            return false;
+
+        Table cur = (Table) _tableMap.get(tab.getName().toUpperCase());
+        if (!cur.equals(tab))
+            return false;
+
+        _tableMap.remove(tab.getName().toUpperCase());
+        _tables = null;
+        SchemaGroup group = getSchemaGroup();
+        if (group != null)
+            group.removeName(tab.getName());
+        tab.remove();
+        return true;
+    }
+
+    /**
+     * Import a table from another schema.	 Note that this method does
+     * <strong>not</strong> import foreign keys, indexes, or unique constraints.
+     */
+    public Table importTable(Table table) {
+        if (table == null)
+            return null;
+
+        Table copy = addTable(table.getName());
+        Column[] cols = table.getColumns();
+        for (int i = 0; i < cols.length; i++)
+            copy.importColumn(cols[i]);
+
+        copy.importPrimaryKey(table.getPrimaryKey());
+        return copy;
+    }
+
+    /**
+     * Return the schema's sequences.
+     */
+    public Sequence[] getSequences() {
+        if (_seqs == null)
+            _seqs = (_seqMap == null) ? new Sequence[0] : (Sequence[])
+                _seqMap.values().toArray(new Sequence[_seqMap.size()]);
+        return _seqs;
+    }
+
+    /**
+     * Return the sequence with the given name, or null if none.
+     */
+    public Sequence getSequence(String name) {
+        if (name == null || _seqMap == null)
+            return null;
+        return (Sequence) _seqMap.get(name.toUpperCase());
+    }
+
+    /**
+     * Add a sequence to the schema.
+     */
+    public Sequence addSequence(String name) {
+        SchemaGroup group = getSchemaGroup();
+        Sequence seq;
+        if (group != null) {
+            group.addName(name, true);
+            seq = group.newSequence(name, this);
+        } else
+            seq = new Sequence(name, this);
+        if (_seqMap == null)
+            _seqMap = new TreeMap();
+        _seqMap.put(name.toUpperCase(), seq);
+        _seqs = null;
+        return seq;
+    }
+
+    /**
+     * Remove the given sequence from the schema.
+     *
+     * @return true if the sequence was removed, false if not in the schema
+     */
+    public boolean removeSequence(Sequence seq) {
+        if (seq == null || _seqMap == null)
+            return false;
+
+        Sequence cur = (Sequence) _seqMap.get(seq.getName().toUpperCase());
+        if (!cur.equals(seq))
+            return false;
+
+        _seqMap.remove(seq.getName().toUpperCase());
+        _seqs = null;
+        SchemaGroup group = getSchemaGroup();
+        if (group != null)
+            group.removeName(seq.getName());
+        seq.remove();
+        return true;
+    }
+
+    /**
+     * Import a sequence from another schema.
+     */
+    public Sequence importSequence(Sequence seq) {
+        if (seq == null)
+            return null;
+
+        Sequence copy = addSequence(seq.getName());
+        copy.setInitialValue(seq.getInitialValue());
+        copy.setIncrement(seq.getIncrement());
+        copy.setAllocate(seq.getAllocate());
+        return copy;
+    }
+
+    public int compareTo(Object other) {
+        String name = getName();
+        String otherName = ((Schema) other).getName();
+        if (name == null && otherName == null)
+            return 0;
+        if (name == null)
+            return 1;
+        if (otherName == null)
+            return -1;
+        return name.compareTo(otherName);
+    }
+
+    public String toString() {
+        return getName();
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaFactory.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaFactory.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaFactory.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,39 @@
+/*
+ * 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.schema;
+
+/**
+ * Factory for {@link SchemaGroup}s. Users can plug in their own factory
+ * implementation, or rely on the ones provided. Most schema factoryies
+ * will probably implement {@link org.apache.openjpa.lib.conf.Configurable} to
+ * receive the system congiguration on construction.
+ *
+ * @author Abe White
+ */
+public interface SchemaFactory {
+
+    /**
+     * Return the schema group for the current object model and database.
+     */
+    public SchemaGroup readSchema();
+
+    /**
+     * Record the schema group after changes may have been made.
+     *
+     * @param schema the schema definition for the entire system
+     */
+    public void storeSchema(SchemaGroup schema);
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGenerator.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGenerator.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGenerator.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGenerator.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,943 @@
+/*
+ * 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.schema;
+
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.sql.DataSource;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.sql.DBDictionary;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.lib.util.Localizer;
+
+/**
+ * The SchemaGenerator creates {@link Schema}s matching the current
+ * database. All schemas are added to the current {@link SchemaGroup}.
+ *  Note that tables whose name starts with "OPENJPA_" will be not be added
+ * to the database schema. This enables the creation of special tables
+ * that will never be dropped by the {@link SchemaTool}.
+ *
+ * @author Abe White
+ */
+public class SchemaGenerator {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (SchemaGenerator.class);
+
+    private final DataSource _ds;
+    private final DBDictionary _dict;
+    private final Log _log;
+    private final Object[][] _allowed;
+    private boolean _indexes = true;
+    private boolean _fks = true;
+    private boolean _pks = true;
+    private boolean _seqs = true;
+    private boolean _openjpaTables = true;
+    private SchemaGroup _group = null;
+
+    private List _listeners = null;
+    private int _schemaObjects = 0;
+
+    /**
+     * Constructor.
+     *
+     * @param conf configuration for connecting to the data store
+     */
+    public SchemaGenerator(JDBCConfiguration conf) {
+        // note: we cannot assert developer capabilities in this tool like
+        // we normally do because this class is also used at runtime
+
+        _ds = conf.getDataSource2(null);
+        _log = conf.getLog(JDBCConfiguration.LOG_SCHEMA);
+
+        // cache this now so that if the conn pool only has 1 connection we
+        // don't conflict later with the open databasemetadata connection
+        _dict = conf.getDBDictionaryInstance();
+
+        // create a table of allowed schema and tables to reflect on
+        _allowed = parseSchemasList(conf.getSchemasList());
+    }
+
+    /**
+     * Given a list of schema names and table names (where table names
+     * are always of the form schema.table, or just .table if the schema is
+     * unknown), creates a table mapping schema name to table list. Returns
+     * null if no args are given. If no tables are given for a particular
+     * schema, maps the schema name to null.
+     */
+    private static Object[][] parseSchemasList(String[] args) {
+        if (args == null || args.length == 0)
+            return null;
+
+        Map schemas = new HashMap();
+        String schema, table;
+        int dotIdx;
+        Collection tables;
+        for (int i = 0; i < args.length; i++) {
+            dotIdx = args[i].indexOf('.');
+            if (dotIdx == -1) {
+                schema = args[i];
+                table = null;
+            } else if (dotIdx == 0) {
+                schema = null;
+                table = args[i].substring(1);
+            } else {
+                schema = args[i].substring(0, dotIdx);
+                table = args[i].substring(dotIdx + 1);
+            }
+
+            // if just a schema name, map schema to null
+            if (table == null && !schemas.containsKey(schema))
+                schemas.put(schema, null);
+            else if (table != null) {
+                tables = (Collection) schemas.get(schema);
+                if (tables == null) {
+                    tables = new LinkedList();
+                    schemas.put(schema, tables);
+                }
+                tables.add(table);
+            }
+        }
+
+        Object[][] parsed = new Object[schemas.size()][2];
+        Map.Entry entry;
+        int idx = 0;
+        for (Iterator itr = schemas.entrySet().iterator(); itr.hasNext();) {
+            entry = (Map.Entry) itr.next();
+            tables = (Collection) entry.getValue();
+
+            parsed[idx][0] = entry.getKey();
+            if (tables != null)
+                parsed[idx][1] = tables.toArray(new String[tables.size()]);
+            idx++;
+        }
+        return parsed;
+    }
+
+    /**
+     * Return whether indexes should be generated. Defaults to true.
+     */
+    public boolean getIndexes() {
+        return _indexes;
+    }
+
+    /**
+     * Set whether indexes should be generated. Defaults to true.
+     */
+    public void setIndexes(boolean indexes) {
+        _indexes = indexes;
+    }
+
+    /**
+     * Return whether foreign keys should be generated. Defaults to true.
+     */
+    public boolean getForeignKeys() {
+        return _fks;
+    }
+
+    /**
+     * Set whether foreign keys should be generated. Defaults to true.
+     */
+    public void setForeignKeys(boolean fks) {
+        _fks = fks;
+    }
+
+    /**
+     * Return whether primary keys should be generated. Defaults to true.
+     */
+    public boolean getPrimaryKeys() {
+        return _pks;
+    }
+
+    /**
+     * Set whether primary keys should be generated. Defaults to true.
+     */
+    public void setPrimaryKeys(boolean pks) {
+        _pks = pks;
+    }
+
+    /**
+     * Return whether sequences should be generated. Defaults to true.
+     */
+    public boolean getSequences() {
+        return _seqs;
+    }
+
+    /**
+     * Set whether sequences should be generated. Defaults to true.
+     */
+    public void setSequences(boolean seqs) {
+        _seqs = seqs;
+    }
+
+    /**
+     * Whether to generate info on special tables used by OpenJPA components
+     * for bookkeeping. Defaults to true.
+     */
+    public boolean getOpenJPATables() {
+        return _openjpaTables;
+    }
+
+    /**
+     * Whether to generate info on special tables used by OpenJPA components
+     * for bookkeeping. Defaults to true.
+     */
+    public void setOpenJPATables(boolean openjpaTables) {
+        _openjpaTables = openjpaTables;
+    }
+
+    /**
+     * Return the current schema group.
+     */
+    public SchemaGroup getSchemaGroup() {
+        if (_group == null)
+            _group = new SchemaGroup();
+        return _group;
+    }
+
+    /**
+     * Set the schema group to add generated schemas to.
+     */
+    public void setSchemaGroup(SchemaGroup group) {
+        _group = group;
+    }
+
+    /**
+     * Generate all schemas set in the configuration. This method also
+     * calls {@link #generateIndexes}, {@link #generatePrimaryKeys}, and
+     * {@link #generateForeignKeys} automatically.
+     */
+    public void generateSchemas()
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-schemas"));
+        generateSchemas(null);
+    }
+
+    /**
+     * Generate the schemas and/or tables named in the given strings.
+     * This method calls {@link #generateIndexes},
+     * {@link #generatePrimaryKeys}, and {@link #generateForeignKeys}
+     * automatically.
+     */
+    public void generateSchemas(String[] schemasAndTables)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-schemas"));
+
+        Object[][] schemaMap;
+        if (schemasAndTables == null || schemasAndTables.length == 0)
+            schemaMap = _allowed;
+        else
+            schemaMap = parseSchemasList(schemasAndTables);
+
+        if (schemaMap == null) {
+            generateSchema(null, null);
+
+            // estimate the number of schema objects we will need to visit
+            // in order to estimate progresss total for any listeners
+            int numTables = getTables(null).size();
+            _schemaObjects += numTables
+                + (_pks ? numTables : 0)
+                + (_indexes ? numTables : 0)
+                + (_fks ? numTables : 0);
+
+            if (_pks)
+                generatePrimaryKeys(null, null);
+            if (_indexes)
+                generateIndexes(null, null);
+            if (_fks)
+                generateForeignKeys(null, null);
+            return;
+        }
+
+        // generate all schemas and tables
+        for (int i = 0; i < schemaMap.length; i++)
+            generateSchema((String) schemaMap[i][0],
+                (String[]) schemaMap[i][1]);
+
+        // generate pks, indexes, fks
+        String schemaName;
+        String[] tableNames;
+        for (int i = 0; i < schemaMap.length; i++) {
+            schemaName = (String) schemaMap[i][0];
+            tableNames = (String[]) schemaMap[i][1];
+
+            // estimate the number of schema objects we will need to visit
+            // in order to estimate progresss total for any listeners
+            int numTables = (tableNames != null) ? tableNames.length
+                : getTables(schemaName).size();
+            _schemaObjects += numTables
+                + (_pks ? numTables : 0)
+                + (_indexes ? numTables : 0)
+                + (_fks ? numTables : 0);
+
+            if (_pks)
+                generatePrimaryKeys(schemaName, tableNames);
+            if (_indexes)
+                generateIndexes(schemaName, tableNames);
+            if (_fks)
+                generateForeignKeys(schemaName, tableNames);
+        }
+    }
+
+    /**
+     * Add a fully-constructed {@link Schema} matching the given database
+     * schema to the current group. No foreign keys are generated because
+     * some keys might span schemas. You must call
+     * {@link #generatePrimaryKeys}, {@link #generateIndexes}, and
+     * {@link #generateForeignKeys} separately.
+     *
+     * @param name the database name of the schema, or null for all schemas
+     * @param tableNames a list of tables to generate in the schema, or null
+     * to generate all tables
+     */
+    public void generateSchema(String name, String[] tableNames)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-schema", name));
+
+        // generate tables, including columns and primary keys
+        Connection conn = _ds.getConnection();
+        DatabaseMetaData meta = conn.getMetaData();
+        try {
+            if (tableNames == null)
+                generateTables(name, null, conn, meta);
+            else
+                for (int i = 0; i < tableNames.length; i++)
+                    generateTables(name, tableNames[i], conn, meta);
+
+            if (_seqs)
+                generateSequences(name, null, conn, meta);
+        } finally {
+            // some databases require a commit after metadata to release locks
+            try {
+                conn.commit();
+            } catch (SQLException se) {
+            }
+            try {
+                conn.close();
+            } catch (SQLException se) {
+            }
+        }
+    }
+
+    /**
+     * Generate primary key information for the given schema. This method
+     * must be called in addition to {@link #generateSchema}. It should
+     * only be called after all schemas are generated. The schema name and
+     * tables array can be null to indicate that indexes should be generated
+     * for all schemas and/or tables.
+     */
+    public void generatePrimaryKeys(String schemaName, String[] tableNames)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-all-primaries", schemaName));
+
+        Connection conn = _ds.getConnection();
+        DatabaseMetaData meta = conn.getMetaData();
+        try {
+            if (tableNames == null)
+                generatePrimaryKeys(schemaName, null, conn, meta);
+            else
+                for (int i = 0; i < tableNames.length; i++)
+                    generatePrimaryKeys(schemaName, tableNames[i], conn, meta);
+        } finally {
+            // some databases require a commit after metadata to release locks
+            try {
+                conn.commit();
+            } catch (SQLException se) {
+            }
+            try {
+                conn.close();
+            } catch (SQLException se) {
+            }
+        }
+    }
+
+    /**
+     * Generate index information for the given schema. This method
+     * must be called in addition to {@link #generateSchema}. It should
+     * only be called after all schemas are generated. The schema name and
+     * tables array can be null to indicate that indexes should be generated
+     * for all schemas and/or tables.
+     */
+    public void generateIndexes(String schemaName, String[] tableNames)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-all-indexes", schemaName));
+
+        Connection conn = _ds.getConnection();
+        DatabaseMetaData meta = conn.getMetaData();
+        try {
+            if (tableNames == null)
+                generateIndexes(schemaName, null, conn, meta);
+            else
+                for (int i = 0; i < tableNames.length; i++)
+                    generateIndexes(schemaName, tableNames[i], conn, meta);
+        } finally {
+            // some databases require a commit after metadata to release locks
+            try {
+                conn.commit();
+            } catch (SQLException se) {
+            }
+            try {
+                conn.close();
+            } catch (SQLException se) {
+            }
+        }
+    }
+
+    /**
+     * Generate foreign key information for the given schema. This method
+     * must be called in addition to {@link #generateSchema}. It should
+     * only be called after all schemas are generated. The schema name and
+     * tables array can be null to indicate that indexes should be generated
+     * for all schemas and/or tables.
+     */
+    public void generateForeignKeys(String schemaName, String[] tableNames)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-all-foreigns", schemaName));
+
+        Connection conn = _ds.getConnection();
+        DatabaseMetaData meta = conn.getMetaData();
+        try {
+            if (tableNames == null)
+                generateForeignKeys(schemaName, null, conn, meta);
+            else
+                for (int i = 0; i < tableNames.length; i++)
+                    generateForeignKeys(schemaName, tableNames[i], conn, meta);
+        } finally {
+            // some databases require a commit after metadata to release locks
+            try {
+                conn.commit();
+            } catch (SQLException se) {
+            }
+            try {
+                conn.close();
+            } catch (SQLException se) {
+            }
+        }
+    }
+
+    /**
+     * Adds all tables matching the given name pattern to the schema.
+     */
+    public void generateTables(String schemaName, String tableName,
+        Connection conn, DatabaseMetaData meta)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-columns", schemaName,
+            tableName));
+        if (_log.isInfoEnabled())
+            _log.info(_loc.get("gen-tables", schemaName, tableName));
+
+        Column[] cols = _dict.getColumns(meta, conn.getCatalog(), schemaName,
+            tableName, null, conn);
+
+        // when we want to get all the columns for all tables, we need to build
+        // a list of tables to verify because some databases (e.g., Postgres)
+        // will include indexes in the list of columns, and there is no way to
+        // distinguish the indexes from proper columns
+        Set tableNames = null;
+        if (tableName == null || "%".equals(tableName)) {
+            Table[] tables = _dict.getTables(meta, conn.getCatalog(),
+                schemaName, tableName, conn);
+            tableNames = new HashSet();
+            for (int i = 0; tables != null && i < tables.length; i++) {
+                if (cols == null)
+                    tableNames.add(tables[i].getName());
+                else
+                    tableNames.add(tables[i].getName().toUpperCase());
+            }
+        }
+
+        // if database can't handle null table name, recurse on each known name
+        if (cols == null && tableName == null) {
+            for (Iterator itr = tableNames.iterator(); itr.hasNext();)
+                generateTables(schemaName, (String) itr.next(), conn, meta);
+            return;
+        }
+
+        SchemaGroup group = getSchemaGroup();
+        Schema schema;
+        Table table;
+        String tableSchema;
+        for (int i = 0; cols != null && i < cols.length; i++) {
+            tableName = cols[i].getTableName();
+            tableSchema = cols[i].getSchemaName();
+            if (tableSchema != null && tableSchema.length() == 0)
+                tableSchema = null;
+
+            // ignore special tables
+            if (!_openjpaTables &&
+                (tableName.toUpperCase().startsWith("OPENJPA_")
+                    || tableName.toUpperCase().startsWith("JDO_"))) // legacy
+                continue;
+            if (_dict.isSystemTable(tableName, tableSchema, schemaName != null))
+                continue;
+
+            // ignore tables not in list, or not allowed by schemas property
+            if (tableNames != null
+                && !tableNames.contains(tableName.toUpperCase()))
+                continue;
+            if (!isAllowedTable(tableSchema, tableName))
+                continue;
+
+            schema = group.getSchema(tableSchema);
+            if (schema == null)
+                schema = group.addSchema(tableSchema);
+
+            table = schema.getTable(tableName);
+            if (table == null) {
+                table = schema.addTable(tableName);
+                if (_log.isTraceEnabled())
+                    _log.trace(_loc.get("col-table", table));
+            }
+
+            if (_log.isTraceEnabled())
+                _log.trace(_loc.get("gen-column", cols[i].getName(), table));
+
+            if (table.getColumn(cols[i].getName()) == null)
+                table.importColumn(cols[i]);
+        }
+    }
+
+    /**
+     * Return whether the given table is allowed by the user's schema list.
+     */
+    private boolean isAllowedTable(String schema, String table) {
+        if (_allowed == null)
+            return true;
+
+        // do case-insensitive comparison on allowed table and schema names
+        String[] tables;
+        String[] anySchemaTables = null;
+        for (int i = 0; i < _allowed.length; i++) {
+            if (_allowed[i][0] == null) {
+                anySchemaTables = (String[]) _allowed[i][1];
+                if (schema == null)
+                    break;
+                continue;
+            }
+            if (!StringUtils.equalsIgnoreCase(schema, (String) _allowed[i][0]))
+                continue;
+
+            if (table == null)
+                return true;
+            tables = (String[]) _allowed[i][1];
+            if (tables == null)
+                return true;
+            for (int j = 0; j < tables.length; j++)
+                if (StringUtils.equalsIgnoreCase(table, tables[j]))
+                    return true;
+        }
+
+        if (anySchemaTables != null) {
+            if (table == null)
+                return true;
+            for (int i = 0; i < anySchemaTables.length; i++)
+                if (StringUtils.equalsIgnoreCase(table, anySchemaTables[i]))
+                    return true;
+        }
+        return false;
+    }
+
+    /**
+     * Generates table primary keys.
+     */
+    public void generatePrimaryKeys(String schemaName, String tableName,
+        Connection conn, DatabaseMetaData meta)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-primary",
+            schemaName, tableName));
+        if (_log.isTraceEnabled())
+            _log.trace(_loc.get("gen-pks", schemaName, tableName));
+
+        // if looking for a non-existant table, just return
+        SchemaGroup group = getSchemaGroup();
+        if (tableName != null && group.findTable(tableName) == null)
+            return;
+
+        // if the database can't use a table name wildcard, recurse on each
+        // concrete table in the requested schema(s)
+        PrimaryKey[] pks = _dict.getPrimaryKeys(meta, conn.getCatalog(),
+            schemaName, tableName, conn);
+        Table table;
+        if (pks == null && tableName == null) {
+            Collection tables = getTables(schemaName);
+            for (Iterator itr = tables.iterator(); itr.hasNext();) {
+                table = (Table) itr.next();
+                generatePrimaryKeys(table.getSchemaName(),
+                    table.getName(), conn, meta);
+            }
+            return;
+        }
+
+        Schema schema;
+        PrimaryKey pk;
+        String name;
+        String colName;
+        for (int i = 0; pks != null && i < pks.length; i++) {
+            schemaName = pks[i].getSchemaName();
+            if (schemaName != null && schemaName.length() == 0)
+                schemaName = null;
+            schema = group.getSchema(schemaName);
+            if (schema == null)
+                continue;
+            table = schema.getTable(pks[i].getTableName());
+            if (table == null)
+                continue;
+
+            colName = pks[i].getColumnName();
+            name = pks[i].getName();
+            if (_log.isTraceEnabled())
+                _log.trace(_loc.get("gen-pk", name, table, colName));
+
+            pk = table.getPrimaryKey();
+            if (pk == null)
+                pk = table.addPrimaryKey(name);
+            pk.addColumn(table.getColumn(colName));
+        }
+    }
+
+    /**
+     * Generates table indexes.
+     */
+    public void generateIndexes(String schemaName, String tableName,
+        Connection conn, DatabaseMetaData meta)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-indexes",
+            schemaName, tableName));
+        if (_log.isTraceEnabled())
+            _log.trace(_loc.get("gen-indexes", schemaName, tableName));
+
+        // if looking for a non-existant table, just return
+        SchemaGroup group = getSchemaGroup();
+        if (tableName != null && group.findTable(tableName) == null)
+            return;
+
+        // if the database can't use a table name wildcard, recurse on each
+        // concrete table in the requested schema(s)
+        Index[] idxs = _dict.getIndexInfo(meta, conn.getCatalog(),
+            schemaName, tableName, false, true, conn);
+        Table table;
+        if (idxs == null && tableName == null) {
+            Collection tables = getTables(schemaName);
+            for (Iterator itr = tables.iterator(); itr.hasNext();) {
+                table = (Table) itr.next();
+                generateIndexes(table.getSchemaName(),
+                    table.getName(), conn, meta);
+            }
+            return;
+        }
+
+        Schema schema;
+        Index idx;
+        String name;
+        String colName;
+        String pkName;
+        for (int i = 0; idxs != null && i < idxs.length; i++) {
+            schemaName = idxs[i].getSchemaName();
+            if (schemaName != null && schemaName.length() == 0)
+                schemaName = null;
+            schema = group.getSchema(schemaName);
+            if (schema == null)
+                continue;
+            table = schema.getTable(idxs[i].getTableName());
+            if (table == null)
+                continue;
+
+            if (table.getPrimaryKey() != null)
+                pkName = table.getPrimaryKey().getName();
+            else
+                pkName = null;
+
+            // statistics don't have names; skip them
+            name = idxs[i].getName();
+            if (name == null || name.length() == 0
+                || (pkName != null && name.equalsIgnoreCase(pkName))
+                || _dict.isSystemIndex(name, table))
+                continue;
+
+            colName = idxs[i].getColumnName();
+            if (table.getColumn(colName) == null)
+                continue;
+
+            if (_log.isTraceEnabled())
+                _log.trace(_loc.get("gen-index", name, table, colName));
+
+            // same index may have multiple rows for multiple cols
+            idx = table.getIndex(name);
+            if (idx == null) {
+                idx = table.addIndex(name);
+                idx.setUnique(idxs[i].isUnique());
+            }
+            idx.addColumn(table.getColumn(colName));
+        }
+    }
+
+    /**
+     * Generates table foreign keys.
+     */
+    public void generateForeignKeys(String schemaName, String tableName,
+        Connection conn, DatabaseMetaData meta)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-foreign",
+            schemaName, tableName));
+        if (_log.isTraceEnabled())
+            _log.trace(_loc.get("gen-fks", schemaName, tableName));
+
+        // if looking for a non-existant table, just return
+        SchemaGroup group = getSchemaGroup();
+        if (tableName != null && group.findTable(tableName) == null)
+            return;
+
+        // if the database can't use a table name wildcard, recurse on each
+        // concrete table in the requested schema(s)
+        ForeignKey[] fks = _dict.getImportedKeys(meta, conn.getCatalog(),
+            schemaName, tableName, conn);
+        Table table;
+        if (fks == null && tableName == null) {
+            Collection tables = getTables(schemaName);
+            for (Iterator itr = tables.iterator(); itr.hasNext();) {
+                table = (Table) itr.next();
+                generateForeignKeys(table.getSchemaName(),
+                    table.getName(), conn, meta);
+            }
+            return;
+        }
+
+        Schema schema;
+        Table pkTable;
+        ForeignKey fk;
+        String name;
+        String pkSchemaName;
+        String pkTableName;
+        String pkColName;
+        String fkColName;
+        int seq;
+        boolean seqWas0 = false; // some drivers incorrectly start at 0
+        Collection invalids = null;
+        for (int i = 0; fks != null && i < fks.length; i++) {
+            schemaName = fks[i].getSchemaName();
+            if (schemaName != null && schemaName.length() == 0)
+                schemaName = null;
+            schema = group.getSchema(schemaName);
+            if (schema == null)
+                continue;
+            table = schema.getTable(fks[i].getTableName());
+            if (table == null)
+                continue;
+
+            name = fks[i].getName();
+            fkColName = fks[i].getColumnName();
+            pkColName = fks[i].getPrimaryKeyColumnName();
+            seq = fks[i].getKeySequence();
+            if (seq == 0)
+                seqWas0 = true;
+            if (seqWas0)
+                seq++;
+
+            // find pk table
+            pkSchemaName = fks[i].getPrimaryKeySchemaName();
+            pkTableName = fks[i].getPrimaryKeyTableName();
+            if (_log.isTraceEnabled())
+                _log.trace(_loc.get("gen-fk", new Object[]{ name, table,
+                    fkColName, pkTableName, pkColName, seq + "" }));
+
+            if (pkSchemaName != null && pkSchemaName.length() > 0)
+                pkTableName = pkSchemaName + "." + pkTableName;
+            pkTable = group.findTable(pkTableName);
+            if (pkTable == null)
+                throw new SQLException(_loc.get("gen-nofktable",
+                    table, pkTableName));
+
+            // this sucks, because it is *not* guaranteed to work;
+            // the fk resultset is ordered by primary key table, then
+            // sequence number within the foreign key (some drivers don't
+            // use sequence numbers correctly either); since fk names
+            // are allowed to be null, all this adds up to the fact
+            // that there is absolutely no way to distinguish between
+            // multiple multi-column fks to the same table; we're going
+            // to rely on fk name here and hope it works
+            fk = table.getForeignKey(name);
+
+            // start a new fk?
+            if (seq == 1 || fk == null) {
+                fk = table.addForeignKey(name);
+                fk.setDeferred(fks[i].isDeferred());
+                fk.setDeleteAction(fks[i].getDeleteAction());
+            }
+
+            if (invalids == null || !invalids.contains(fk)) {
+                try {
+                    fk.join(table.getColumn(fkColName),
+                        pkTable.getColumn(pkColName));
+                } catch (IllegalArgumentException iae) {
+                    if (_log.isWarnEnabled())
+                        _log.warn(_loc.get("bad-join", iae.toString()));
+                    if (invalids == null)
+                        invalids = new HashSet();
+                    invalids.add(fk);
+                }
+            }
+        }
+
+        // remove invalid fks
+        if (invalids != null) {
+            for (Iterator itr = invalids.iterator(); itr.hasNext();) {
+                fk = (ForeignKey) itr.next();
+                fk.getTable().removeForeignKey(fk);
+            }
+        }
+    }
+
+    /**
+     * Adds all sequences matching the given name pattern to the schema.
+     */
+    public void generateSequences(String schemaName, String sequenceName,
+        Connection conn, DatabaseMetaData meta)
+        throws SQLException {
+        fireGenerationEvent(_loc.get("generating-sequences", schemaName));
+        if (_log.isInfoEnabled())
+            _log.info(_loc.get("gen-seqs", schemaName, sequenceName));
+
+        Sequence[] seqs = _dict.getSequences(meta, conn.getCatalog(),
+            schemaName, sequenceName, conn);
+
+        SchemaGroup group = getSchemaGroup();
+        Schema schema;
+        String sequenceSchema;
+        for (int i = 0; seqs != null && i < seqs.length; i++) {
+            sequenceName = seqs[i].getName();
+            sequenceSchema = seqs[i].getSchemaName();
+            if (sequenceSchema != null && sequenceSchema.length() == 0)
+                sequenceSchema = null;
+
+            // ignore special tables
+            if (!_openjpaTables &&
+                (sequenceName.toUpperCase().startsWith("OPENJPA_")
+                    || sequenceName.toUpperCase().startsWith("JDO_"))) // legacy
+                continue;
+            if (_dict.isSystemSequence(sequenceName, sequenceSchema,
+                schemaName != null))
+                continue;
+            if (!isAllowedTable(sequenceSchema, null))
+                continue;
+
+            schema = group.getSchema(sequenceSchema);
+            if (schema == null)
+                schema = group.addSchema(sequenceSchema);
+            if (schema.getSequence(sequenceName) == null)
+                schema.addSequence(sequenceName);
+        }
+    }
+
+    /**
+     * Notify any listeners that a schema object was generated. Returns
+     * true if generation should continue.
+     */
+    private void fireGenerationEvent(Object schemaObject)
+        throws SQLException {
+        if (schemaObject == null)
+            return;
+        if (_listeners == null || _listeners.size() == 0)
+            return;
+
+        Event e = new Event(schemaObject, _schemaObjects);
+        for (Iterator i = _listeners.iterator(); i.hasNext();) {
+            Listener l = (Listener) i.next();
+            if (!l.schemaObjectGenerated(e))
+                throw new SQLException(_loc.get("refresh-cancelled"));
+        }
+    }
+
+    /**
+     * Adds a listener for schema generation events.
+     *
+     * @param l the listener to add
+     */
+    public void addListener(Listener l) {
+        if (_listeners == null)
+            _listeners = new LinkedList();
+        _listeners.add(l);
+    }
+
+    /**
+     * Removes a schema generation listener for schema events.
+     *
+     * @param l the listener to remove
+     * @return true if it was successfully removed
+     */
+    public boolean removeListener(Listener l) {
+        return _listeners != null && _listeners.remove(l);
+    }
+
+    /**
+     * Return all tables for the given schema name, or all tables in
+     * the schema group if null is given.
+     */
+    private Collection getTables(String schemaName) {
+        SchemaGroup group = getSchemaGroup();
+        if (schemaName != null) {
+            Schema schema = group.getSchema(schemaName);
+            if (schema == null)
+                return Collections.EMPTY_LIST;
+            return Arrays.asList(schema.getTables());
+        }
+
+        Schema[] schemas = group.getSchemas();
+        Collection tables = new LinkedList();
+        for (int i = 0; i < schemas.length; i++)
+            tables.addAll(Arrays.asList(schemas[i].getTables()));
+        return tables;
+    }
+
+    /**
+     * A listener for a potentially lengthy schema generation process.
+     */
+    public static interface Listener {
+
+        boolean schemaObjectGenerated(Event e);
+    }
+
+    /**
+     * An event corresponding to the generation of a schema object.
+     */
+    public class Event
+        extends EventObject {
+
+        private final int _total;
+
+        public Event(Object ob, int total) {
+            super(ob);
+            _total = total;
+        }
+
+        public int getTotal() {
+            return _total;
+        }
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGroup.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGroup.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGroup.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaGroup.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,401 @@
+/*
+ * 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.schema;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+/**
+ * Represents a grouping of schemas used in a database.
+ *
+ * @author Abe White
+ */
+public class SchemaGroup
+    extends NameSet
+    implements Cloneable {
+
+    private Map _schemaMap = null;
+
+    // cache
+    private Schema[] _schemas = null;
+
+    /**
+     * Return all schemas.
+     */
+    public Schema[] getSchemas() {
+        if (_schemas == null)
+            _schemas = (_schemaMap == null) ? new Schema[0] : (Schema[])
+                _schemaMap.values().toArray(new Schema[_schemaMap.size()]);
+        return _schemas;
+    }
+
+    /**
+     * Return the schema with the given name, or null if none.
+     */
+    public Schema getSchema(String name) {
+        if (_schemaMap == null)
+            return null;
+        if (name != null)
+            name = name.toUpperCase();
+        return (Schema) _schemaMap.get(name);
+    }
+
+    /**
+     * Add a schema to the group.
+     */
+    public Schema addSchema() {
+        return addSchema(null);
+    }
+
+    /**
+     * Add a schema to the group.
+     */
+    public Schema addSchema(String name) {
+        addName(name, false);
+        Schema schema = newSchema(name);
+        if (name != null)
+            name = name.toUpperCase();
+        if (_schemaMap == null)
+            _schemaMap = new HashMap();
+        _schemaMap.put(name, schema);
+        _schemas = null;
+        return schema;
+    }
+
+    /**
+     * Remove the given schema from the group.
+     *
+     * @return true if the schema was removed, false if not in the group
+     */
+    public boolean removeSchema(Schema schema) {
+        if (schema == null)
+            return false;
+
+        String name = schema.getName();
+        if (name != null)
+            name = name.toUpperCase();
+        Schema rem = (Schema) _schemaMap.get(name);
+        if (schema.equals(rem)) {
+            _schemaMap.remove(name);
+            removeName(schema.getName());
+            _schemas = null;
+            schema.remove();
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Import a schema from another group. Foreign keys are not imported.
+     */
+    public Schema importSchema(Schema schema) {
+        if (schema == null)
+            return null;
+
+        Schema copy = addSchema(schema.getName());
+        Sequence[] seqs = schema.getSequences();
+        for (int i = 0; i < seqs.length; i++)
+            copy.importSequence(seqs[i]);
+
+        Table[] tables = schema.getTables();
+        Index[] idxs;
+        Unique[] unqs;
+        Table tab;
+        for (int i = 0; i < tables.length; i++) {
+            tab = copy.importTable(tables[i]);
+            idxs = tables[i].getIndexes();
+            for (int j = 0; j < idxs.length; j++)
+                tab.importIndex(idxs[j]);
+            unqs = tables[i].getUniques();
+            for (int j = 0; j < unqs.length; j++)
+                tab.importUnique(unqs[j]);
+        }
+        return copy;
+    }
+
+    /**
+     * Return true if the given table is known to exist. While
+     * {@link #findTable} may exhibit dynamic behavior in some schema group
+     * implementations, this method only returns true if the table has been
+     * added to this group or is known to exist in the database.
+     */
+    public boolean isKnownTable(Table table) {
+        return findTable(table) != null;
+    }
+
+    /**
+     * Return true if the given table is known to exist. While
+     * {@link #findTable} may exhibit dynamic behavior in some schema group
+     * implementations, this method only returns true if the table has been
+     * added to this group or is known to exist in the database.
+     */
+    public boolean isKnownTable(String name) {
+        return findTable(name) != null;
+    }
+
+    /**
+     * Find the equivalent of the given table in this schema group. The
+     * given table that may have come from another schema group.
+     */
+    public Table findTable(Table table) {
+        return findTable(table.getFullName());
+    }
+
+    /**
+     * Find the table with the given name in the group, using '.' as the
+     * catalog separator. Returns null if no table found.
+     */
+    public Table findTable(String name) {
+        if (name == null)
+            return null;
+
+        int dotIdx = name.indexOf('.');
+        if (dotIdx != -1) {
+            String schemaName = name.substring(0, dotIdx);
+            name = name.substring(dotIdx + 1);
+            Schema schema = getSchema(schemaName);
+            if (schema != null)
+                return schema.getTable(name);
+        } else {
+            Schema[] schemas = getSchemas();
+            Table tab;
+            for (int i = 0; i < schemas.length; i++) {
+                tab = schemas[i].getTable(name);
+                if (tab != null)
+                    return tab;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Return true if the given sequence is known to exist. While
+     * {@link #findSequence} may exhibit dynamic behavior in some schema group
+     * implementations, this method only returns true if the sequence has been
+     * added to this group or is known to exist in the database.
+     */
+    public boolean isKnownSequence(Sequence seq) {
+        return findSequence(seq) != null;
+    }
+
+    /**
+     * Return true if the given sequence is known to exist. While
+     * {@link #findSequence} may exhibit dynamic behavior in some schema group
+     * implementations, this method only returns true if the sequence has been
+     * added to this group or is known to exist in the database.
+     */
+    public boolean isKnownSequence(String name) {
+        return findSequence(name) != null;
+    }
+
+    /**
+     * Find the equivalent of the given sequence in this schema group. The
+     * given sequence that may have come from another schema group.
+     */
+    public Sequence findSequence(Sequence seq) {
+        return findSequence(seq.getFullName());
+    }
+
+    /**
+     * Find the sequence with the given name in the group, using '.' as the
+     * catalog separator. Returns null if no sequence found.
+     */
+    public Sequence findSequence(String name) {
+        if (name == null)
+            return null;
+
+        int dotIdx = name.indexOf('.');
+        if (dotIdx != -1) {
+            String schemaName = name.substring(0, dotIdx);
+            name = name.substring(dotIdx + 1);
+            Schema schema = getSchema(schemaName);
+            if (schema != null)
+                return schema.getSequence(name);
+        } else {
+            Schema[] schemas = getSchemas();
+            Sequence seq;
+            for (int i = 0; i < schemas.length; i++) {
+                seq = schemas[i].getSequence(name);
+                if (seq != null)
+                    return seq;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Find all foreign keys exported by a given primary key (all foreign
+     * keys that link to the primary key).
+     */
+    public ForeignKey[] findExportedForeignKeys(PrimaryKey pk) {
+        if (pk == null)
+            return new ForeignKey[0];
+
+        Schema[] schemas = getSchemas();
+        Table[] tabs;
+        ForeignKey[] fks;
+        Collection exports = new LinkedList();
+        for (int i = 0; i < schemas.length; i++) {
+            tabs = schemas[i].getTables();
+            for (int j = 0; j < tabs.length; j++) {
+                fks = tabs[j].getForeignKeys();
+                for (int k = 0; k < fks.length; k++) {
+                    if (fks[k].getPrimaryKeyTable() != null
+                        && pk.equals(fks[k].getPrimaryKeyTable().
+                        getPrimaryKey()))
+                        exports.add(fks[k]);
+                }
+            }
+        }
+        return (ForeignKey[]) exports.toArray(new ForeignKey[exports.size()]);
+    }
+
+    /**
+     * Remove unreferenced or emtpy components from the schema.
+     */
+    public void removeUnusedComponents() {
+        Schema[] schemas = getSchemas();
+        Table[] tabs;
+        Column[] cols;
+        Sequence[] seqs;
+        PrimaryKey pk;
+        ForeignKey[] fks;
+        for (int i = 0; i < schemas.length; i++) {
+            seqs = schemas[i].getSequences();
+            for (int j = 0; j < seqs.length; j++)
+                if (seqs[j].getRefCount() == 0)
+                    schemas[i].removeSequence(seqs[j]);
+
+            tabs = schemas[i].getTables();
+            for (int j = 0; j < tabs.length; j++) {
+                pk = tabs[j].getPrimaryKey();
+                fks = tabs[j].getForeignKeys();
+                cols = tabs[j].getColumns();
+
+                if (pk != null && pk.getRefCount() == 0)
+                    tabs[j].removePrimaryKey();
+
+                for (int k = 0; k < fks.length; k++)
+                    if (fks[k].getRefCount() == 0)
+                        tabs[j].removeForeignKey(fks[k]);
+
+                for (int k = 0; k < cols.length; k++)
+                    if (cols[k].getRefCount() == 0)
+                        tabs[j].removeColumn(cols[k]);
+
+                if (tabs[j].getColumns().length == 0)
+                    schemas[i].removeTable(tabs[j]);
+            }
+
+            if (schemas[i].getTables().length == 0)
+                removeSchema(schemas[i]);
+        }
+    }
+
+    public Object clone() {
+        SchemaGroup clone = newInstance();
+        clone.copy(this);
+        return clone;
+    }
+
+    /**
+     * Create a new instance of this class.
+     */
+    protected SchemaGroup newInstance() {
+        return new SchemaGroup();
+    }
+
+    /**
+     * Copy cloneable state from the given instance.
+     */
+    protected void copy(SchemaGroup group) {
+        Schema[] schemas = group.getSchemas();
+        for (int i = 0; i < schemas.length; i++)
+            importSchema(schemas[i]);
+
+        // have to do fks after all schemas are imported
+        Table[] tabs;
+        ForeignKey[] fks;
+        Schema clone;
+        for (int i = 0; i < schemas.length; i++) {
+            tabs = schemas[i].getTables();
+            for (int j = 0; j < tabs.length; j++) {
+                fks = tabs[j].getForeignKeys();
+                for (int k = 0; k < fks.length; k++)
+                    getSchema(schemas[i].getName()).getTable
+                        (tabs[j].getName()).importForeignKey(fks[k]);
+            }
+        }
+    }
+
+    /**
+     * Return a new schema with the given name.
+     */
+    protected Schema newSchema(String name) {
+        return new Schema(name, this);
+    }
+
+    /**
+     * Return a new sequence with the given name and owner schema.
+     */
+    protected Sequence newSequence(String name, Schema schema) {
+        return new Sequence(name, schema);
+    }
+
+    /**
+     * Return a new table with the given name and owner schema.
+     */
+    protected Table newTable(String name, Schema schema) {
+        return new Table(name, schema);
+    }
+
+    /**
+     * Return a new column with the given name and owner table.
+     */
+    protected Column newColumn(String name, Table table) {
+        return new Column(name, table);
+    }
+
+    /**
+     * Return a new primary key with the given name and owner table.
+     */
+    protected PrimaryKey newPrimaryKey(String name, Table table) {
+        return new PrimaryKey(name, table);
+    }
+
+    /**
+     * Return a new index with the given name and owner table.
+     */
+    protected Index newIndex(String name, Table table) {
+        return new Index(name, table);
+    }
+
+    /**
+     * Return a new unique constraint with the given name and owner table.
+     */
+    protected Unique newUnique(String name, Table table) {
+        return new Unique(name, table);
+    }
+
+    /**
+     * Return a new foreign key with the given name and owner table.
+     */
+    protected ForeignKey newForeignKey(String name, Table table) {
+        return new ForeignKey(name, table);
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaParser.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaParser.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaParser.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaParser.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,62 @@
+/*
+ * 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.schema;
+
+import org.apache.openjpa.lib.meta.MetaDataParser;
+
+/**
+ * Interface class for parers that read schema information. Parsers
+ * will place all parsed schemas into the current {@link SchemaGroup}, set
+ * via the {@link #setSchemaGroup} method. This allows parsing of
+ * multiple files into a single schema group.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public interface SchemaParser
+    extends MetaDataParser {
+
+    /**
+     * Delay resolution of foreign key constraints until
+     * {@link #resolveConstraints} is called. This allows you to parse
+     * multiple resources where a foreign key in one resource might refer
+     * to a table in another.
+     */
+    public boolean getDelayConstraintResolve();
+
+    /**
+     * Delay resolution of foreign key constraints until
+     * {@link #resolveConstraints} is called. This allows you to parse
+     * multiple resources where a foreign key in one resource might refer
+     * to a table in another.
+     */
+    public void setDelayConstraintResolve(boolean delay);
+
+    /**
+     * Return the current schema group.
+     */
+    public SchemaGroup getSchemaGroup();
+
+    /**
+     * Set the current schema group; this clears all state from the last group.
+     */
+    public void setSchemaGroup(SchemaGroup group);
+
+    /**
+     * If this parser is in delayed resolve mode, resolve all constraints.
+     */
+    public void resolveConstraints();
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaSerializer.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaSerializer.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaSerializer.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaSerializer.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,78 @@
+/*
+ * 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.schema;
+
+import org.apache.openjpa.lib.meta.MetaDataSerializer;
+
+/**
+ * Interface for schema serializers. Serializers work at the fine-grained
+ * fine-grained table level to allow you to split schemas among multiple files.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public interface SchemaSerializer
+    extends MetaDataSerializer {
+
+    /**
+     * Return the set of tables that will be serialized.
+     */
+    public Table[] getTables();
+
+    /**
+     * Add the given table to the set of tables that will be serialized.
+     */
+    public void addTable(Table table);
+
+    /**
+     * Remove the given table from the set to be serialized.
+     *
+     * @return true if table was removed, false if not in set
+     */
+    public boolean removeTable(Table table);
+
+    /**
+     * Add the given schema's objects to the set of objects that will be
+     * serialized.
+     */
+    public void addAll(Schema schema);
+
+    /**
+     * Add all the objects in the given group to the set of objects that
+     * will be serialized.
+     */
+    public void addAll(SchemaGroup group);
+
+    /**
+     * Remove the given schema's objects from the set to be serialized.
+     *
+     * @return true if any objects in schema removed, false if none in set
+     */
+    public boolean removeAll(Schema schema);
+
+    /**
+     * Remove all schemas in the given group from the set to be serialized.
+     *
+     * @return true if any objects in the group were removed, false if
+     * none in set
+     */
+    public boolean removeAll(SchemaGroup group);
+
+    /**
+     * Clear the set of objects to be serialized.
+     */
+    public void clear();
+}

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