Revision: 3660
Author: [email protected]
Date: Wed Jun 30 12:59:24 2010
Log: NEW - bug 2458: Create Critic Manager
http://trillian.sqlpower.ca/bugzilla/show_bug.cgi?id=2458

Added in a critic to check for duplicate names in support of replacing the quick fix system. Added in a start and end method to the critics to allow critics to keep state of each run and to know when to setup and tear down its state. Removed the getWarnings method from the DDLGenerator interface. This is the first step of cleaning up the current quick fix system but more is to come.
http://code.google.com/p/power-architect/source/detail?r=3660

Added:
/trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/DuplicateNameCritic.java
Modified:
 /trunk/regress/ca/sqlpower/architect/ddl/GenericDDLGeneratorTest.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/DDLGenerator.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/GenericDDLGenerator.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/LiquibaseDDLGenerator.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/OracleDDLGenerator.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/PostgresDDLGenerator.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Critic.java
/trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticAndSettings.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticManager.java
 /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Criticizer.java
/trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/AlphaNumericNameCritic.java /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/OraclePhysicalNameCritic.java /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/PhysicalNameCritic.java

=======================================
--- /dev/null
+++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/DuplicateNameCritic.java Wed Jun 30 12:59:24 2010
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2010, SQL Power Group Inc.
+ *
+ * This file is part of SQL Power Architect.
+ *
+ * SQL Power Architect is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * SQL Power Architect is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package ca.sqlpower.architect.ddl.critic.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import ca.sqlpower.architect.ddl.critic.CriticAndSettings;
+import ca.sqlpower.architect.ddl.critic.Criticism;
+import ca.sqlpower.architect.ddl.critic.QuickFix;
+import ca.sqlpower.sqlobject.SQLColumn;
+import ca.sqlpower.sqlobject.SQLIndex;
+import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLRelationship;
+import ca.sqlpower.sqlobject.SQLTable;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * This critic will create a warning for objects that have the same name if they + * are of conflicting types. This means some objects, like columns in different + * tables, can have the same name but a sequence cannot have the same name as a
+ * table because they are at the same level in a database.
+ */
+public class DuplicateNameCritic extends CriticAndSettings {
+
+    /**
+     * Stores all of the top level target database objects by name for the
+ * current run of the critics. The definition of top level is any object
+     * that is in the target database that would be at the same level in a
+     * database when written out to a DDL script. This includes tables,
+     * relationships, indices, and sequences.
+     * <p>
+ * Note: sequences are represented by columns in this map as there is no
+     * sequence object.
+     */
+ private Multimap<String, SQLObject> topLevelPhysicalNameMap = ArrayListMultimap.create();
+
+    /**
+     * Maps each parent table to the columns in the table that we have
+ * critiqued. This way we can find if there are columns with matching column
+     * names.
+     */
+ private Multimap<SQLTable, SQLColumn> columnPhysicalNameMap = ArrayListMultimap.create();
+
+    public DuplicateNameCritic() {
+ super(StarterPlatformTypes.GENERIC.getName(), "Error on objects with the same name.");
+    }
+
+    @Override
+    public void start() {
+        super.start();
+        topLevelPhysicalNameMap.clear();
+        columnPhysicalNameMap.clear();
+    }
+
+    @Override
+    public void end() {
+        super.end();
+        topLevelPhysicalNameMap.clear();
+        columnPhysicalNameMap.clear();
+    }
+
+    public List<Criticism> criticize(Object subject) {
+ if (!(subject instanceof SQLObject)) return Collections.emptyList();
+
+        List<Criticism> criticisms = new ArrayList<Criticism>();
+        if (subject instanceof SQLColumn) {
+            final SQLColumn col = (SQLColumn) subject;
+            SQLTable parent = col.getParent();
+
+            int count = 0;
+            for (SQLColumn otherCol : columnPhysicalNameMap.get(parent)) {
+                if (col.getPhysicalName().equals(otherCol)) {
+                    count++;
+                }
+            }
+            if (count > 0) {
+ final String newPhysicalName = col.getPhysicalName() + "_" + count;
+                criticisms.add(new Criticism(subject,
+ "Duplicate physical name \"" + col.getPhysicalName() + "\"", this, + new QuickFix("Replace physical name with " + newPhysicalName) {
+                            @Override
+                            public void apply() {
+                                col.setPhysicalName(newPhysicalName);
+                            }
+                        }));
+            }
+            columnPhysicalNameMap.put(parent, col);
+        }
+ if (subject instanceof SQLTable || subject instanceof SQLRelationship || + subject instanceof SQLIndex || subject instanceof SQLColumn) {
+            final SQLObject obj = (SQLObject) subject;
+            String physicalName = obj.getPhysicalName();
+            if (obj instanceof SQLColumn) {
+ physicalName = ((SQLColumn) obj).getAutoIncrementSequenceName();
+            }
+ Collection<SQLObject> sameNameObjects = topLevelPhysicalNameMap.get(physicalName);
+            if (!sameNameObjects.isEmpty()) {
+ final String newPhysicalName = physicalName + "_" + sameNameObjects.size(); + criticisms.add(new Criticism(subject, "Duplicate physical name \"" + physicalName + "\"", this, + new QuickFix("Replace physical name with " + newPhysicalName) {
+                            @Override
+                            public void apply() {
+                                if (obj instanceof SQLColumn) {
+ ((SQLColumn) obj).setAutoIncrementSequenceName(newPhysicalName);
+                                } else {
+                                    obj.setPhysicalName(newPhysicalName);
+                                }
+                            }
+                }));
+            }
+            topLevelPhysicalNameMap.put(physicalName, obj);
+        }
+        return criticisms;
+    }
+
+}
=======================================
--- /trunk/regress/ca/sqlpower/architect/ddl/GenericDDLGeneratorTest.java Thu May 27 07:42:00 2010 +++ /trunk/regress/ca/sqlpower/architect/ddl/GenericDDLGeneratorTest.java Wed Jun 30 12:59:24 2010
@@ -19,35 +19,16 @@

 package ca.sqlpower.architect.ddl;

-import ca.sqlpower.sqlobject.SQLColumn;
+import java.sql.Types;
+import java.util.List;
+
 import junit.framework.TestCase;
-import ca.sqlpower.sqlobject.SQLRelationship;
+import ca.sqlpower.sqlobject.SQLColumn;
 import ca.sqlpower.sqlobject.SQLTable;
 import ca.sqlpower.sqlobject.SQLType;
import ca.sqlpower.sqlobject.SQLTypePhysicalPropertiesProvider.PropertyType;

-import java.sql.Types;
-import java.util.List;
-
 public class GenericDDLGeneratorTest extends TestCase {
-
-    /**
- * Regression testing for bug 1354. If a relationship is forward engineered
-     * but has no columns then it should be skipped.
-     */
-    public void testSkipRelationWithNoColumns() throws Exception {
-        GenericDDLGenerator ddl = new GenericDDLGenerator();
-        SQLRelationship r = new SQLRelationship();
-        r.setName("Test Relation");
-        SQLTable pkTable = new SQLTable();
-        pkTable.initFolders(true);
-        SQLTable fkTable = new SQLTable();
-        fkTable.initFolders(true);
-        r.attachRelationship(pkTable, fkTable, true);
-        ddl.addRelationship(r);
-
-        assertEquals(1, ddl.getWarnings().size());
-    }

        public void testGenerateComment() throws Exception {
                GenericDDLGenerator ddl = new GenericDDLGenerator();
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/DDLGenerator.java Tue May 18 11:21:10 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/DDLGenerator.java Wed Jun 30 12:59:24 2010
@@ -261,11 +261,6 @@
      */
     public void setTypeMap(Map<Integer, GenericTypeDescriptor> argTypeMap);

-    /**
-     * Returns {...@link #warnings}.
-     */
-    public List<DDLWarning> getWarnings();
-
     /**
      * See {...@link #targetCatalog}.
      *
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/GenericDDLGenerator.java Mon Jun 14 11:54:52 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/GenericDDLGenerator.java Wed Jun 30 12:59:24 2010
@@ -43,7 +43,6 @@
 import ca.sqlpower.sqlobject.SQLObject;
 import ca.sqlpower.sqlobject.SQLObjectException;
 import ca.sqlpower.sqlobject.SQLRelationship;
-import ca.sqlpower.sqlobject.SQLSequence;
 import ca.sqlpower.sqlobject.SQLTable;
 import ca.sqlpower.sqlobject.SQLType;
 import ca.sqlpower.sqlobject.SQLTypePhysicalPropertiesProvider;
@@ -117,16 +116,6 @@
         */
        protected Map<String, SQLObject> topLevelNames;

-       /**
-        * This list contains 0 or more {...@link NameChangeWarning} objects.  
It is
-        * populated as statements are added to the
-        * <code>ddlStatements</code> list.  If non-empty, this list of
-        * warnings should be presented to the user before the generated
-        * DDL is saved or executed (to give them a chance to fix the
-        * warnings and try again).
-        */
-       protected List<DDLWarning> warnings;
-
        /**
         * The name of the catalog in the target database that the
         * generated DDL statements should create the objects in.  Not all
@@ -157,7 +146,6 @@

public GenericDDLGenerator(boolean allowConnection) throws SQLException {
         this.allowConnection = allowConnection;
-        warnings = new ArrayList<DDLWarning>();
         ddlStatements = new ArrayList<DDLStatement>();
         ddl = new StringBuffer(500);
         println("");
@@ -202,7 +190,6 @@
* @see ca.sqlpower.architect.ddl.DDLGenerator#generateDDLStatements(Collection)
         */
public final List<DDLStatement> generateDDLStatements(Collection<SQLTable> tables) throws SQLException, SQLObjectException {
-        warnings = new ArrayList<DDLWarning>();
                ddlStatements = new ArrayList<DDLStatement>();
                ddl = new StringBuffer(500);
         topLevelNames = new CaseInsensitiveHashMap();
@@ -360,7 +347,6 @@
                firstColumn = true;

                if (r.getChildren().isEmpty()) {
- warnings.add(new RelationshipMapsNoColumnsDDLWarning(r.getPkTable(), r.getFkTable()));
                    errorMsg.append("Warning: Relationship has no columns to 
map:\n");
                }

@@ -371,7 +357,6 @@
                        // checks the fk column and pk column are the same type,
                        // generates DDLWarning if not the same.
                        if (ArchitectUtils.columnTypesDiffer(c.getType(), 
fkCol.getType())) {
- warnings.add(new RelationshipColumnsTypesMismatchDDLWarning(c, fkCol));
                            typesMismatchMsg.append("        " + c + " -- " + fkCol + 
"\n");
                        }
                        // make sure this is unique
@@ -393,18 +378,6 @@
errorMsg.append("Warning: Column types mismatch in the following column mapping(s):\n");
                    errorMsg.append(typesMismatchMsg.toString());
                }
-
- // sanity check for SET NULL and SET DEFAULT delete rules, whether or not DB supports them - for (SQLRelationship.ColumnMapping cm : r.getChildren(ColumnMapping.class)) {
-            UpdateDeleteRule deleteRule = r.getDeleteRule();
-            SQLColumn fkcol = cm.getFkColumn();
- if (deleteRule == UpdateDeleteRule.SET_NULL && !fkcol.isDefinitelyNullable()) {
-                warnings.add(new SetNullOnNonNullableColumnWarning(fkcol));
-            } else if (deleteRule == UpdateDeleteRule.SET_DEFAULT &&
- (fkcol.getDefaultValue() == null || fkcol.getDefaultValue().length() == 0)) { - warnings.add(new SetDefaultOnColumnWithNoDefaultWarning(fkcol));
-            }
-        }

                if (supportsDeleteAction(r)) {
                    String deleteActionClause = getDeleteActionClause(r);
@@ -414,23 +387,9 @@
                        sql.append("\n").append(deleteActionClause);
                    }
                } else {
-                   warnings.add(new UnsupportedFeatureDDLWarning(
- getName() + " does not support " + r.getName() + "'s delete action", r)); errorMsg.append("Warning: " + getName() + " does not support this relationship's " +
                            "delete action (" + r.getDeleteRule() + ").\n");
                }
-
- // sanity check for SET NULL and SET DEFAULT update rules, whether or not DB supports them - for (SQLRelationship.ColumnMapping cm : r.getChildren(SQLRelationship.ColumnMapping.class)) {
-            UpdateDeleteRule updateRule = r.getUpdateRule();
-            SQLColumn fkcol = cm.getFkColumn();
- if (updateRule == UpdateDeleteRule.SET_NULL && !fkcol.isDefinitelyNullable()) {
-                warnings.add(new SetNullOnNonNullableColumnWarning(fkcol));
-            } else if (updateRule == UpdateDeleteRule.SET_DEFAULT &&
- (fkcol.getDefaultValue() == null || fkcol.getDefaultValue().length() == 0)) { - warnings.add(new SetDefaultOnColumnWithNoDefaultWarning(fkcol));
-            }
-        }

                if (supportsUpdateAction(r)) {
             String updateActionClause = getUpdateActionClause(r);
@@ -440,8 +399,6 @@
                 sql.append("\n").append(updateActionClause);
             }
                } else {
-            warnings.add(new UnsupportedFeatureDDLWarning(
- getName() + " does not support " + r.getName() + "'s update action", r)); errorMsg.append("Warning: " + getName() + " does not support this relationship's " +
                     "update action (" + r.getUpdateRule() + ").\n");
                }
@@ -456,8 +413,6 @@
                        sql.append("\n").append(deferrabilityClause);
                    }
                } else {
-                   warnings.add(new UnsupportedFeatureDDLWarning(
- getName() + " does not support " + r.getName() + "'s deferrability policy", r)); errorMsg.append("Warning: " + getName() + " does not support this relationship's " +
                            "deferrability policy (" + r.getDeferrability() + 
").\n");
                }
@@ -817,34 +772,9 @@
                    if (td == null) {
throw new NullPointerException("Current type map does not have entry for default datatype!");
                    }
-                   GenericTypeDescriptor oldType = new GenericTypeDescriptor
-                   (c.getSourceDataTypeName(), c.getType(), c.getPrecision(),
-                           null, null, c.getNullable(), false, false);
-                   oldType.determineScaleAndPrecision();
-                   TypeMapDDLWarning o = new TypeMapDDLWarning(c, 
String.format(
- "Type '%s' of column '%s' in table '%s' is unknown in the target platform",
-                    SQLType.getTypeName(c.getType()),
-                    c.getPhysicalName(),
-                    c.getParent().getPhysicalName()), oldType, td);
-                  if (!contains(warnings, o)) {
-                      warnings.add(o);
-                  }
         }
         return td;
     }
-
-    private boolean contains(List<DDLWarning> list, TypeMapDDLWarning o) {
-        Iterator<DDLWarning> iterator = list.iterator();
-        while (iterator.hasNext()) {
-            Object next = iterator.next();
-            if (next instanceof TypeMapDDLWarning) {
- if (((TypeMapDDLWarning)next).getMessage().equals(o.getMessage())) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }

        public void addTable(SQLTable t) throws SQLException, 
SQLObjectException {
Map<String, SQLObject> colNameMap = new HashMap<String, SQLObject>(); // for detecting duplicate column names
@@ -1111,13 +1041,6 @@
        public void setCon(Connection argCon) {
                this.con = argCon;
        }
-
-       /**
-        * Returns {...@link #warnings}.
-        */
-       public List<DDLWarning> getWarnings() {
-               return warnings;
-       }

        /**
         * See {...@link #targetCatalog}.
@@ -1183,157 +1106,14 @@
(so.getPhysicalName() != null && !so.getPhysicalName().trim().equals(""))) {
                    String physicalName = so.getPhysicalName();
logger.debug("The physical name for this SQLObject is: " + physicalName);
-                   if (physicalName.lastIndexOf(' ') != -1) {
-                       String renameTo = (toIdentifier(physicalName));
-                warnings.add(new InvalidNameDDLWarning(
-                               String.format("Name %s has white spaces", 
physicalName),
-                               Arrays.asList(new SQLObject[] {so}),
- String.format("Rename %s to %s", physicalName, renameTo ),
-                               so, renameTo));
-                   }
                } else {
                    so.setPhysicalName(toIdentifier(so.getName()));
                }
         String physicalName = so.getPhysicalName();
-        if(isReservedWord(physicalName)) {
-            String renameTo = physicalName   + "_1";
-            warnings.add(new InvalidNameDDLWarning(
-                    String.format("%s is a reserved word", physicalName),
-                    Arrays.asList(new SQLObject[] { so }),
- String.format("Rename %s to %s", physicalName, renameTo),
-                    so, renameTo));
-            return physicalName;
-        }
         logger.debug("The logical name field now is: " + so.getName());
-        logger.debug("The physical name field now is: " + physicalName);
-        int pointIndex = so.getPhysicalName().lastIndexOf('.');
- if (!so.getPhysicalName().substring(pointIndex+1,pointIndex+2).matches("[a-zA-Z]")){
-            String renameTo;
-            if (so instanceof SQLTable) {
-                renameTo = "Table_" + so.getPhysicalName();
-            } else if (so instanceof SQLColumn) {
-                renameTo = "Column_" + so.getPhysicalName();
-            } else if (so instanceof SQLIndex) {
-                renameTo = "Index_" + so.getPhysicalName();
-            } else {
-                renameTo = "X_" + so.getPhysicalName();
-            }
-            warnings.add(new InvalidNameDDLWarning(
- String.format("Name %s starts with a non-alpha character", physicalName),
-                    Arrays.asList(new SQLObject[] { so }),
- String.format("Rename %s to %s", physicalName, renameTo),
-                    so, renameTo));
-            return physicalName;
-        }
-
- logger.debug("transform identifier result: " + so.getPhysicalName()); - // XXX should change checkDupName(Map where, so.getPhysicalName(), so, "Duplicate Physical Name", so.getName());
-
-        String physicalName2 = so.getPhysicalName();
-        SQLObject object = dupCheck.get(physicalName2);
-        if (object == null) {
-                       dupCheck.put(physicalName2, so);
-        } else {
-
-            int count = 1;
-            String renameTo2;
-            SQLObject object2;
-            do {
-                renameTo2 = physicalName2 + "_" + count;
-                object2 = dupCheck.get(renameTo2);
-                count++;
-            } while (object2 != null);
-
-            String message;
-            if (so instanceof SQLColumn) {
- message = String.format("Column name %s in table %s already in use",
-                        so.getPhysicalName(),
-                        ((SQLColumn) so).getParent().getPhysicalName());
-            } else {
- message = String.format("Global name %s already in use", physicalName2);
-            }
-            logger.debug("Rename to : " + renameTo2);
-
-            warnings.add(new InvalidNameDDLWarning(
-                    message,
-                    Arrays.asList(new SQLObject[] { so }),
- String.format("Rename %s to %s", physicalName2, renameTo2),
-                    so, renameTo2));
-
-            dupCheck.put(renameTo2, so);
-
-               }

                return so.getPhysicalName();
        }
-
-       /**
-     * Generate, set, and return a valid identifier for this SQLSequence.
- * Has a side effect of changing the given SQLColumn's autoIncrementSequenceName.
-     * @throws SQLObjectException
-     *
-     * @param dupCheck  The Map to check for duplicate names
- * @param seq The SQLSequence to generate, set and return a valid identifier for. - * @param col The SQLColumn to where the side effect should occur.
-     */
- protected String createSeqPhysicalName(Map<String, SQLObject> dupCheck, SQLSequence seq, SQLColumn col) { - logger.debug("transform identifier source: " + seq.getPhysicalName());
-        seq.setPhysicalName(toIdentifier(seq.getName()));
-        String physicalName = seq.getPhysicalName();
-        if(isReservedWord(physicalName)) {
-            String renameTo = physicalName   + "_1";
-            warnings.add(new InvalidSeqNameDDLWarning(
-                    String.format("%s is a reserved word", physicalName),
-                    seq, col,
- String.format("Rename %s to %s", physicalName, renameTo),
-                    renameTo));
-            return physicalName;
-        }
-
-        int pointIndex = seq.getPhysicalName().lastIndexOf('.');
- if (!seq.getName().substring(pointIndex+1,pointIndex+2).matches("[a-zA-Z]")){
-            String renameTo = "Seq_" + seq.getName();
-            warnings.add(new InvalidSeqNameDDLWarning(
- String.format("Name %s starts with a non-alpha character", physicalName),
-                    seq, col,
- String.format("Rename %s to %s", physicalName, renameTo),
-                    renameTo));
-            return physicalName;
-        }
-
- logger.debug("transform identifier result: " + seq.getPhysicalName()); - // XXX should change checkDupName(Map where, so.getPhysicalName(), so, "Duplicate Physical Name", so.getName());
-
-        String physicalName2 = seq.getPhysicalName();
-        SQLObject object = dupCheck.get(physicalName2);
-        if (object == null) {
-            dupCheck.put(physicalName2, seq);
-        } else {
-
-            int count = 1;
-            String renameTo2;
-            SQLObject object2;
-            do {
-                renameTo2 = physicalName2 + "_" + count;
-                object2 = dupCheck.get(renameTo2);
-                count++;
-            } while (object2 != null);
-
- String message = String.format("Global name %s already in use", physicalName);
-            logger.debug("Rename to : " + renameTo2);
-
-            warnings.add(new InvalidSeqNameDDLWarning(
-                    message,
-                    seq, col,
- String.format("Rename %s to %s", physicalName, renameTo2),
-                    renameTo2));
-
-            dupCheck.put(renameTo2, seq);
-
-        }
-
-        return seq.getPhysicalName();
-    }

     /**
* Generates a standard <code>DROP TABLE $tablename</code> command. Should work on most platforms.
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/LiquibaseDDLGenerator.java Sun Jun 20 10:57:59 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/LiquibaseDDLGenerator.java Wed Jun 30 12:59:24 2010
@@ -281,7 +281,6 @@
                firstColumn = true;

                if (r.getChildren().isEmpty()) {
- warnings.add(new RelationshipMapsNoColumnsDDLWarning(r.getPkTable(), r.getFkTable()));
                    errorMsg.append("Warning: Relationship has no columns to 
map:\n");
                }

@@ -292,7 +291,6 @@
                        // checks the fk column and pk column are the same type,
                        // generates DDLWarning if not the same.
                        if (ArchitectUtils.columnTypesDiffer(c.getType(), 
fkCol.getType())) {
- warnings.add(new RelationshipColumnsTypesMismatchDDLWarning(c, fkCol));
                            typesMismatchMsg.append("        " + c + " -- " + fkCol + 
"\n");
                        }
                        // make sure this is unique
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/OracleDDLGenerator.java Fri Jun 25 11:31:05 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/OracleDDLGenerator.java Wed Jun 30 12:59:24 2010
@@ -408,7 +408,7 @@
             if (c.isAutoIncrement()) {
SQLSequence seq = new SQLSequence(toIdentifier(c.getAutoIncrementSequenceName()));
                 print("\nCREATE SEQUENCE ");
-                print(createSeqPhysicalName(topLevelNames, seq, c));
+                print(seq.getName());
                 endStatement(StatementType.CREATE, seq);
             }
         }
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/PostgresDDLGenerator.java Fri Jun 25 11:31:05 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/PostgresDDLGenerator.java Wed Jun 30 12:59:24 2010
@@ -392,7 +392,7 @@
             if (c.isAutoIncrement()) {
SQLSequence seq = new SQLSequence(toIdentifier(c.getAutoIncrementSequenceName()));
                 print("\nCREATE SEQUENCE ");
- print(toQualifiedName(createSeqPhysicalName(topLevelNames, seq, c)));
+                print(toQualifiedName(seq.getName()));
                 endStatement(StatementType.CREATE, seq);
             }
         }
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Critic.java Mon Jun 14 14:02:56 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Critic.java Wed Jun 30 12:59:24 2010
@@ -36,6 +36,15 @@
  * Classes of this type must be immutable.
  */
 public interface Critic {
+
+    /**
+     * Start must be called once before calling criticize on this critic.
+ * Calling start on a critic allows the critic to initialize any state for + * the critic for the duration of this run. If the criticism of the state of + * the system is to be executed again end must be called before start is
+     * called again.
+     */
+    public void start();

     /**
      * Analyzes the subject and returns a set of criticisms if there are
@@ -44,6 +53,13 @@
      */
     public List<Criticism> criticize(Object subject);

+    /**
+     * End must be called when criticizing the current set of objects is
+ * complete. Calling end allows the critic to clean up any state before it
+     * is executed again.
+     */
+    public void end();
+
     /**
* The error level this critic was defined to be at when it was created. * The severity should not change even if settings in the project change
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticAndSettings.java Tue Jun 29 13:26:19 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticAndSettings.java Wed Jun 30 12:59:24 2010
@@ -86,6 +86,12 @@
      */
     private final String platformType;

+    /**
+     * If true the critic has been started and is not allowed to be started
+     * again until it has been ended.
+     */
+    private boolean started;
+
     /**
      * @param platformType
* A string that will group critics together. This is normally a
@@ -103,6 +109,24 @@
         severity = Severity.ERROR;
         setName(name);
     }
+
+    /**
+ * Most critics need to do nothing in terms of state. Only select critics
+     * should ever need to override this method.
+     */
+    public void start() {
+ if (started) throw new IllegalStateException("The critic " + getName() +
+                " has been started already.");
+        started = true;
+    }
+
+    /**
+ * Most critics need to do nothing in terms of state. Only select critics
+     * should ever need to override this method.
+     */
+    public void end() {
+        started = false;
+    }

     @Mutator
     public void setSeverity(Severity severity) {
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticManager.java Tue Jun 29 13:26:19 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/CriticManager.java Wed Jun 30 12:59:24 2010
@@ -30,6 +30,7 @@
 import ca.sqlpower.architect.ddl.critic.impl.AlphaNumericNameCritic;
import ca.sqlpower.architect.ddl.critic.impl.AlphaNumericSequenceNameCritic;
 import ca.sqlpower.architect.ddl.critic.impl.DB2UnsupportedFeaturesCritic;
+import ca.sqlpower.architect.ddl.critic.impl.DuplicateNameCritic;
 import ca.sqlpower.architect.ddl.critic.impl.EmptyRelationshipCritic;
 import ca.sqlpower.architect.ddl.critic.impl.H2UnsupportedFeaturesCritic;
import ca.sqlpower.architect.ddl.critic.impl.HSQLDBUnsupportedFeaturesCritic;
@@ -82,6 +83,7 @@
                 new AlphaNumericSequenceNameCritic(),
                 new SetDefaultOnColumnWithNoDefaultCritic(),
                 new SetNullOnNonNullableColumnCritic(),
+                new DuplicateNameCritic(),
                 //DB2
                 new DB2UnsupportedFeaturesCritic(),
                 //H2
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Criticizer.java Mon Jun 14 08:38:33 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/Criticizer.java Wed Jun 30 12:59:24 2010
@@ -52,7 +52,16 @@
      * descendants if it is an {...@link SPObject}.
      */
     public List<Criticism> criticize(Object subject) {
-        return recursivelyCriticize(subject);
+        try {
+            for (Critic c : critics) {
+                c.start();
+            }
+            return recursivelyCriticize(subject);
+        } finally {
+            for (Critic c : critics) {
+                c.end();
+            }
+        }
     }

     /**
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/AlphaNumericNameCritic.java Wed Jun 30 10:01:27 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/AlphaNumericNameCritic.java Wed Jun 30 12:59:24 2010
@@ -34,17 +34,4 @@
         setName(Messages.getString("AlphaNumericNameCritic.name"));
     }

-    @Override
-    public String correctPhysicalName(String existingName) {
-        StringBuffer buffer = new StringBuffer(existingName.length());
-        for (int i = 0; i < existingName.length(); i++) {
-            if (existingName.charAt(i) == ' ') {
-                buffer.append('_');
- } else if (getLegalNamePattern().matcher(Character.toString(existingName.charAt(i))).matches()) {
-                buffer.append(existingName.charAt(i));
-            }
-        }
-        return buffer.toString();
-    }
-
-}
+}
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/OraclePhysicalNameCritic.java Wed Jun 30 10:01:27 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/OraclePhysicalNameCritic.java Wed Jun 30 12:59:24 2010
@@ -33,18 +33,5 @@
Pattern.compile("^[a-z_][a-z0-9_]*$", Pattern.CASE_INSENSITIVE),
                 30);
     }
-
-    @Override
-    public String correctPhysicalName(String existingName) {
-        StringBuffer buffer = new StringBuffer(existingName.length());
-        for (int i = 0; i < existingName.length(); i++) {
-            if (existingName.charAt(i) == ' ') {
-                buffer.append('_');
- } else if (getLegalNamePattern().matcher(Character.toString(existingName.charAt(i))).matches()) {
-                buffer.append(existingName.charAt(i));
-            }
-        }
-        return buffer.toString();
-    }

 }
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/PhysicalNameCritic.java Wed Jun 30 10:01:27 2010 +++ /trunk/src/main/java/ca/sqlpower/architect/ddl/critic/impl/PhysicalNameCritic.java Wed Jun 30 12:59:24 2010
@@ -31,7 +31,10 @@
 import ca.sqlpower.object.annotation.Accessor;
 import ca.sqlpower.object.annotation.Constructor;
 import ca.sqlpower.object.annotation.ConstructorParameter;
+import ca.sqlpower.sqlobject.SQLColumn;
+import ca.sqlpower.sqlobject.SQLIndex;
 import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLTable;
 import ca.sqlpower.sqlobject.SQLIndex.Column;
 import ca.sqlpower.sqlobject.SQLRelationship.ColumnMapping;

@@ -39,7 +42,7 @@
* Criticizes the physical name of all SQLObjects based on the parameters given
  * to the constructor.
  */
-public abstract class PhysicalNameCritic extends CriticAndSettings {
+public class PhysicalNameCritic extends CriticAndSettings {

     private final Pattern legalNamePattern;
     private final int maxNameLength;
@@ -111,7 +114,7 @@
         }

         if (!getLegalNamePattern().matcher(physName).matches()) {
-            final String newLogicalName = correctPhysicalName(physName);
+ final String newLogicalName = correctPhysicalName(so, physName);
             criticisms.add(new Criticism(
                     so,
                     "Physical name not legal for " + so.getPhysicalName(),
@@ -129,12 +132,32 @@
     }

     /**
- * This method will be given the existing physical name of an object being - * criticized that does not match the pattern for valid physical names and - * it will return a valid physical name for the object that passes the legal + * This method will be given the subject object being criticized and its + * physical name that does not match the pattern for valid physical names and it + * will return a valid physical name for the object that passes the legal
      * name pattern.
      */
-    public abstract String correctPhysicalName(String existingName);
+ public String correctPhysicalName(Object subject, String existingName) {
+        StringBuffer buffer = new StringBuffer(existingName.length());
+        for (int i = 0; i < existingName.length(); i++) {
+            if (existingName.charAt(i) == ' ') {
+                buffer.append('_');
+ } else if (getLegalNamePattern().matcher(Character.toString(existingName.charAt(i))).matches()) {
+                buffer.append(existingName.charAt(i));
+            } else if (i == 0) {
+                if (subject instanceof SQLTable) {
+                    buffer.append("Table_" + existingName.charAt(i));
+                } else if (subject instanceof SQLColumn) {
+                    buffer.append("Column_" + existingName.charAt(i));
+                } else if (subject instanceof SQLIndex) {
+                    buffer.append("Index_" + existingName.charAt(i));
+                } else {
+                    buffer.append("X_" + existingName.charAt(i));
+                }
+            }
+        }
+        return buffer.toString();
+    }

     @Accessor
     public Pattern getLegalNamePattern() {

Reply via email to