Author: jfuerth
Date: Sat May 30 11:58:02 2009
New Revision: 3079

Added:
   trunk/src/ca/sqlpower/architect/ddl/critic/
   trunk/src/ca/sqlpower/architect/ddl/critic/Critic.java
   trunk/src/ca/sqlpower/architect/ddl/critic/Criticism.java
   trunk/src/ca/sqlpower/architect/ddl/critic/Criticizer.java
   trunk/src/ca/sqlpower/architect/ddl/critic/PhysicalNameCritic.java
   trunk/src/ca/sqlpower/architect/ddl/critic/PrimaryKeyCritic.java
   trunk/src/ca/sqlpower/architect/ddl/critic/QuickFix.java
trunk/src/ca/sqlpower/architect/ddl/critic/RelationshipMappingTypeCritic.java
   trunk/src/ca/sqlpower/architect/ddl/critic/critic_wip_notes.txt
   trunk/src/ca/sqlpower/architect/swingui/critic/
   trunk/src/ca/sqlpower/architect/swingui/critic/CriticismTableModel.java
   trunk/src/ca/sqlpower/architect/swingui/critic/CriticizeAction.java
Modified:
   trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java

Log:
First try at a critic system. Some of the stuff in the ca.sqlpower.architect.critic package will have to move to other packages (that haven't been created yet)--right now I'm mostly keeping stuff in the same place because I'm not sure which packages we'll end up wanting in the end.

Comments welcome/encouraged. :)

Added: trunk/src/ca/sqlpower/architect/ddl/critic/Critic.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/Critic.java Sat May 30 11:58:02 2009
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+import java.util.List;
+
+public interface Critic<S> {
+
+    public List<Criticism<S>> criticize(S subject);
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/Criticism.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/Criticism.java Sat May 30 11:58:02 2009
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Criticism<S> {
+
+    private final S subject;
+    private final String description;
+    private final QuickFix[] fixes;
+
+    public Criticism(S subject, String description, QuickFix ... fixes) {
+        this.subject = subject;
+        this.description = description;
+        this.fixes = fixes;
+    }
+
+    public S getSubject() {
+        return subject;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public List<QuickFix> getFixes() {
+        return Arrays.asList(fixes);
+    }
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/Criticizer.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/Criticizer.java Sat May 30 11:58:02 2009
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Criticizer<S> {
+
+    private List<Critic<S>> critics;
+    private List<Criticism<S>> criticisms;
+
+    public Criticizer(List<Critic<S>> critics) {
+        this.critics = new ArrayList<Critic<S>>(critics);
+        criticisms = new ArrayList<Criticism<S>>();
+    }
+
+    public void criticize(S subject) {
+        for (Critic<S> critic : critics) {
+            // TODO wipe out the criticisms we're about to replace
+            List<Criticism<S>> newCriticisms = critic.criticize(subject);
+            criticisms.addAll(newCriticisms);
+ // TODO record the critic-subject combination so it can be wiped out later
+            // TODO fire event(s) about new criticisms
+        }
+    }
+
+    /**
+     * Returns a linear view of the criticisms.
+     * <p>
+     * XXX decide what should dictate the order
+     *
+     * @return an unmodifiable list of criticisms
+     */
+    public List<Criticism<S>> getCriticisms() {
+        return criticisms;
+    }
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/PhysicalNameCritic.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/PhysicalNameCritic.java Sat May 30 11:58:02 2009
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import ca.sqlpower.sqlobject.SQLObject;
+
+public class PhysicalNameCritic implements Critic<SQLObject> {
+
+    private final Pattern legalNamePattern;
+    private final int maxNameLength;
+    private final String platformName;
+
+ public PhysicalNameCritic(String platformName, Pattern legalNamePattern, int maxNameLength) {
+        this.platformName = platformName;
+        this.legalNamePattern = legalNamePattern;
+        this.maxNameLength = maxNameLength;
+
+    }
+
+    public List<Criticism<SQLObject>> criticize(final SQLObject so) {
+        String physName = so.getPhysicalName();
+
+        if (physName == null) return Collections.emptyList();
+
+ List<Criticism<SQLObject>> criticisms = new ArrayList<Criticism<SQLObject>>();
+        if (physName.length() > maxNameLength) {
+            criticisms.add(new Criticism<SQLObject>(
+                    so,
+                    "Physical name too long for " + platformName,
+ new QuickFix("Truncate name to " + maxNameLength + " characters") {
+                        public void apply() {
+ if (so.getPhysicalName() != null && so.getPhysicalName().length() > maxNameLength) { + so.setPhysicalName(so.getPhysicalName().substring(maxNameLength));
+                            }
+                        }
+                    }));
+        }
+        if (!legalNamePattern.matcher(physName).matches()) {
+            criticisms.add(new Criticism<SQLObject>(
+                    so,
+                    "Physical name not legal for " + platformName
+                    // TODO: need replacement pattern to enable quickfix
+                    ));
+        }
+
+        return criticisms;
+    }
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/PrimaryKeyCritic.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/PrimaryKeyCritic.java Sat May 30 11:58:02 2009
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLTable;
+
+public class PrimaryKeyCritic implements Critic<SQLObject> {
+
+    public List<Criticism<SQLObject>> criticize(final SQLObject so) {
+        if (!(so instanceof SQLTable)) return Collections.emptyList();
+        SQLTable t = (SQLTable) so;
+ List<Criticism<SQLObject>> criticisms = new ArrayList<Criticism<SQLObject>>();
+        if (t.getPkSize() == 0) {
+ criticisms.add(new Criticism<SQLObject>(t, "Table has no primary key defined"));
+        }
+        return criticisms;
+    }
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/QuickFix.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/QuickFix.java Sat May 30 11:58:02 2009
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+public abstract class QuickFix {
+
+    private final String description;
+
+    public QuickFix(String description) {
+        this.description = description;
+    }
+
+    public abstract void apply();
+
+    public String getDescription() {
+        return description;
+    }
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/RelationshipMappingTypeCritic.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/RelationshipMappingTypeCritic.java Sat May 30 11:58:02 2009
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import ca.sqlpower.architect.ArchitectUtils;
+import ca.sqlpower.sqlobject.SQLColumn;
+import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLRelationship;
+import ca.sqlpower.sqlobject.SQLTable;
+
+public class RelationshipMappingTypeCritic implements Critic<SQLObject> {
+
+    public List<Criticism<SQLObject>> criticize(SQLObject so) {
+ if (!(so instanceof SQLRelationship)) return Collections.emptyList();
+        SQLRelationship subject = (SQLRelationship) so;
+ List<Criticism<SQLObject>> criticisms = new ArrayList<Criticism<SQLObject>>();
+        for (SQLRelationship.ColumnMapping cm : subject.getMappings()) {
+ if (ArchitectUtils.columnsDiffer(cm.getFkColumn(), cm.getPkColumn())) {
+                final SQLColumn parentColumn = cm.getPkColumn();
+                final SQLTable parentTable = parentColumn.getParentTable();
+                final SQLColumn childColumn = cm.getFkColumn();
+                final SQLTable childTable = childColumn.getParentTable();
+                criticisms.add(new Criticism<SQLObject>(
+                        subject,
+ "Columns related by FK constraint have different types", + new QuickFix("Change type of " + childTable.getName() + "." + childColumn.getName() + " (child column) to parent's type") {
+                            @Override
+                            public void apply() {
+ childColumn.setType(parentColumn.getType()); + childColumn.setPrecision(parentColumn.getPrecision()); + childColumn.setScale(parentColumn.getScale());
+                            }
+                        },
+ new QuickFix("Change type of " + parentTable.getName() + "." + parentColumn.getName() + " (parent column) to child's type") {
+                            @Override
+                            public void apply() {
+ parentColumn.setType(childColumn.getType()); + parentColumn.setPrecision(childColumn.getPrecision()); + parentColumn.setScale(childColumn.getScale());
+                            }
+                        }
+                ));
+            }
+        }
+        return criticisms;
+    }
+
+}

Added: trunk/src/ca/sqlpower/architect/ddl/critic/critic_wip_notes.txt
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/ddl/critic/critic_wip_notes.txt Sat May 30 11:58:02 2009
@@ -0,0 +1,61 @@
+The critics system is a work in progress. This file documents the progress of that work.
+It is organized into three sections:
+
+1. Outstanding items I know I need to implement
+2. Problems and/or design questions I have not yet made a decision about
+3. Reminders about pitfalls I anticipate I might run into in the future if I'm not vigilant
+
+
+1. TODO:
+
+*TableCellRenderer for SQLObjects (so we get nice icons)
+*Severity for criticisms (share severity enum with validation API? move it up into the library's core?)
+*Icon in table for criticism severity
+*Underline criticized things in playpen
+*Badge criticized things in dbtree
+*nice type name routine/method that shows type name and optionally precision,scale (could be in SQLColumn or SQLObjectUtils)
+ *use this in relationship mapping criticizer
+ *use this in tablepane renderer as well!
+*Preferences API and GUI for selecting which critics to use (and to configure the ones that need it) +*disperse classes into the appropriate places (including migrating into library)
+
+2. Things I'm not sure about:
+
+* is it actually useful for a critic to return a list of criticisms?
+  it would be nicer to write a critic if it could return 0 or 1 criticisms.
+ OTOH, the relationship mapping critic wants to be able to comment on several
+  different mappings in the same relationship.
+
+* should a critic be written to criticize exactly one thing? for example,
+ the first critic I wrote was for checking the physical name of a SQLObject. + It checks both the length of the name as well as its legality (by matching
+  it with a provided regex). Should this be two critics?
+
+* should a criticizer be disposable or reusable? I think it would be much simpler + if disposable, but then things like the table model would keep losing their state
+  (due to a full structure change every time anything changes)
+
+* can we use the JAR SPI system to enumerate the critics that currently exist in
+  the classpath?
+
+* how can we improve the use of generics so a critic like PrimaryKeyCritic can implement
+  Critic<SQLTable> instead of the overly-general Critic<SQLObject>?
+ * how about making an AbstractSQLObjectCritic<S extends SQLObject> implements Critic<SQLObject> + and have subclasses provide the single type they're interested in (SQLObject is legal if you want + to do your own type filtering). This would let us easily ignore things like SQLTable.Folder and
+    SQLRelationship.ColumnMapping, which never need direct criticism
+
+
+3. Things to keep in mind:
+
+* it would be nice if criticisms were stored in such a way that it's easy to + invalidate/reevaluate only the necessary objects whenever a change takes place.
+  For example:
+ * PrimaryKeyCritic: The primaryKeySize attribute of the SQLTable in question + * PhysicalNameCritic: Just the physicalName property of the object with the disagreeable name
+   * RelationshipMappingTypeCritic:
+ * The type, precision, and scale of the parent and child columns in the mapping
+     * The mapping itself (shrink or grow)
+ Something else to consider here is how to handle the disappearance of existing criticized
+   objects and the appearance of new objects to criticize.
+

Modified: trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java
==============================================================================
--- trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java (original) +++ trunk/src/ca/sqlpower/architect/swingui/RelationalPlayPenFactory.java Sat May 30 11:58:02 2009
@@ -49,6 +49,7 @@

 import ca.sqlpower.architect.layout.LineStraightenerLayout;
 import ca.sqlpower.architect.swingui.action.AutoLayoutAction;
+import ca.sqlpower.architect.swingui.critic.CriticizeAction;
 import ca.sqlpower.architect.swingui.event.ItemSelectionEvent;
 import ca.sqlpower.architect.swingui.event.ItemSelectionListener;
 import ca.sqlpower.architect.swingui.event.PlayPenContentEvent;
@@ -118,6 +119,8 @@
             mi.setAction(layoutAction);
             menu.add(mi);

+            menu.add(new CriticizeAction(session));
+
             if (pp.isDebugEnabled()) {
                 menu.addSeparator();
                 mi = new JMenuItem("Show Relationships"); //$NON-NLS-1$

Added: trunk/src/ca/sqlpower/architect/swingui/critic/CriticismTableModel.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/critic/CriticismTableModel.java Sat May 30 11:58:02 2009
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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.swingui.critic;
+
+import javax.swing.table.AbstractTableModel;
+
+import ca.sqlpower.architect.ddl.critic.Criticism;
+import ca.sqlpower.architect.ddl.critic.Criticizer;
+
+public class CriticismTableModel extends AbstractTableModel {
+
+    private final Criticizer<?> criticizer;
+
+    public CriticismTableModel(Criticizer<?> criticizer) {
+        this.criticizer = criticizer;
+    }
+
+    public int getColumnCount() {
+        return 2;
+    }
+
+    public int getRowCount() {
+        return criticizer.getCriticisms().size();
+    }
+
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        Criticism<?> rowVal = criticizer.getCriticisms().get(rowIndex);
+        if (columnIndex == 0) {
+            return rowVal.getSubject();
+        } else if (columnIndex == 1) {
+            return rowVal.getDescription();
+        } else {
+            throw new IllegalArgumentException(
+ "This table has " + getColumnCount() + " columns, and I " +
+                    "was asked for column " + columnIndex);
+        }
+    }
+
+}

Added: trunk/src/ca/sqlpower/architect/swingui/critic/CriticizeAction.java
==============================================================================
--- (empty file)
+++ trunk/src/ca/sqlpower/architect/swingui/critic/CriticizeAction.java Sat May 30 11:58:02 2009
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2009, SQL Power Group Inc.
+ *
+ * This file is part of Power*Architect.
+ *
+ * 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.
+ *
+ * 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.swingui.critic;
+
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import javax.swing.JDialog;
+import javax.swing.JScrollPane;
+
+import ca.sqlpower.architect.ddl.critic.Critic;
+import ca.sqlpower.architect.ddl.critic.Criticizer;
+import ca.sqlpower.architect.ddl.critic.PhysicalNameCritic;
+import ca.sqlpower.architect.ddl.critic.PrimaryKeyCritic;
+import ca.sqlpower.architect.ddl.critic.RelationshipMappingTypeCritic;
+import ca.sqlpower.architect.swingui.ArchitectSwingSession;
+import ca.sqlpower.architect.swingui.action.AbstractArchitectAction;
+import ca.sqlpower.sqlobject.SQLDatabase;
+import ca.sqlpower.sqlobject.SQLObject;
+import ca.sqlpower.sqlobject.SQLObjectException;
+import ca.sqlpower.sqlobject.SQLRelationship;
+import ca.sqlpower.sqlobject.SQLTable;
+import ca.sqlpower.swingui.SPSUtils;
+import ca.sqlpower.swingui.table.FancyExportableJTable;
+
+/**
+ * Proof-of-concept action that criticizes a whole SQLObject tree and pops up + * a window with the results. This will be replaced by a system that does criticisms
+ * "in the background" on a more continual basis.
+ */
+public class CriticizeAction extends AbstractArchitectAction {
+
+    public CriticizeAction(ArchitectSwingSession session) {
+ super(session, "Criticize Data Model...", "Evaluates the data model for potential problems and suggests fixes");
+    }
+
+    public void actionPerformed(ActionEvent e) {
+ List<Critic<SQLObject>> critics = new ArrayList<Critic<SQLObject>>(); + critics.add(new PhysicalNameCritic("Oracle", Pattern.compile("^[a-z_][a-z0-9_]*$", Pattern.CASE_INSENSITIVE), 30));
+        critics.add(new PrimaryKeyCritic());
+        critics.add(new RelationshipMappingTypeCritic());
+ Criticizer<SQLObject> criticizer = new Criticizer<SQLObject>(critics);
+        try {
+            recursivelyCriticize(session.getTargetDatabase(), criticizer);
+        } catch (SQLObjectException ex) {
+ throw new RuntimeException("Unexpected exception (because playpen is already populted)", ex);
+        }
+
+ FancyExportableJTable table = new FancyExportableJTable(new CriticismTableModel(criticizer)); + JDialog d = SPSUtils.makeOwnedDialog(session.getPlayPen(), "Data Model Evaluation");
+        SPSUtils.makeJDialogCancellable(d, null);
+        d.setContentPane(new JScrollPane(table));
+        d.pack();
+        d.setSize(table.getPreferredSize().width, d.getHeight());
+        d.setLocationRelativeTo(session.getPlayPen());
+        d.setVisible(true);
+    }
+
+    /**
+     *
+     * @param root
+     *            The SQLObject to criticize
+     * @param criticizer
+     *            The criticizer that will examine the subtree at root and
+     *            accumulate criticisms about it
+     * @throws SQLObjectException
+ * if the (sub)tree under root is not already populated, and an
+     *             attempt to populate it fails
+     */
+    @SuppressWarnings("unchecked")
+ private void recursivelyCriticize(SQLObject root, Criticizer<SQLObject> criticizer) throws SQLObjectException {
+
+        // skip types that don't warrant criticism
+        if ( (!(root instanceof SQLDatabase)) &&
+             (!(root instanceof SQLTable.Folder)) &&
+             (!(root instanceof SQLRelationship.ColumnMapping)) ) {
+            criticizer.criticize(root);
+        }
+
+        for (SQLObject child : (List<SQLObject>) root.getChildren()) {
+            if (child instanceof SQLTable.Folder<?> &&
+ ((SQLTable.Folder) child).getType() == SQLTable.Folder.IMPORTED_KEYS) { + // skip contents of every imported keys folder, or else we will visit every relationship twice
+                continue;
+            }
+            recursivelyCriticize(child, criticizer);
+        }
+    }
+}

Reply via email to