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);
+ }
+ }
+}