Revision: 3790
Author: [email protected]
Date: Tue Jul 27 09:04:00 2010
Log: Fixed a bug introduced by the new user defined types and domain
snapshots feature. Adding in new snapshots must update all of the existing
user defined type's upstream type references. A new upstream type updating
listener handles this case by listening to child added events on
ArchitectProject where the child UserDefineSQLTypeSnapshot is not a domain
snapshot. It looks through all of the descendant UserDefinedSQLTypes where
its upstream type's UUID is equal to the snapshot's original UUID, and
updates the upstream type references to the new snapshot type.
The SQLTypeTreeModel has also been changed so that it only retrieves data
types and domains directly from the session when the model is first
created. Subsequent method calls within the model that define the tree
model's structure should only reflect the model at creation time, and not
any updates that happen afterwards.
http://code.google.com/p/power-architect/source/detail?r=3790
Added:
/trunk/src/main/java/ca/sqlpower/architect/enterprise/UpstreamTypeUpdaterListener.java
Modified:
/trunk/src/main/java/ca/sqlpower/architect/ArchitectSessionImpl.java
/trunk/src/main/java/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java
/trunk/src/main/java/ca/sqlpower/architect/swingui/SQLTypeTreeModel.java
=======================================
--- /dev/null
+++
/trunk/src/main/java/ca/sqlpower/architect/enterprise/UpstreamTypeUpdaterListener.java
Tue Jul 27 09:04:00 2010
@@ -0,0 +1,91 @@
+/*
+ * 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.enterprise;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ca.sqlpower.architect.ArchitectProject;
+import ca.sqlpower.architect.ArchitectSession;
+import ca.sqlpower.object.AbstractPoolingSPListener;
+import ca.sqlpower.object.SPChildEvent;
+import ca.sqlpower.object.SPListener;
+import ca.sqlpower.sqlobject.SQLDatabase;
+import ca.sqlpower.sqlobject.SQLObjectException;
+import ca.sqlpower.sqlobject.SQLObjectUtils;
+import ca.sqlpower.sqlobject.UserDefinedSQLType;
+import ca.sqlpower.sqlobject.UserDefinedSQLTypeSnapshot;
+
+/**
+ * This {...@link SPListener} listens for newly added
+ * {...@link UserDefinedSQLTypeSnapshot}s on an {...@link ArchitectProject}.
When a
+ * {...@link UserDefinedSQLTypeSnapshot} is added, all the
+ * {...@link UserDefinedSQLType}s upstream type previously referencing the
+ * snapshot's original UUID needs to be updated to the snapshot's
+ * {...@link UserDefinedSQLType} UUID.
+ */
+public class UpstreamTypeUpdaterListener extends AbstractPoolingSPListener
{
+
+ /**
+ * The {...@link ArchitectSession} where its workspace's
+ * {...@link UserDefinedSQLTypeSnapshot}s and the references to the
+ * {...@link UserDefinedSQLType} upstream types need to be updated.
+ */
+ private final ArchitectSession session;
+
+ /**
+ * Creates a new {...@link UpstreamTypeUpdaterListener}.
+ *
+ * @param session
+ * The {...@link ArchitectSession} where its workspace's
+ * {...@link UserDefinedSQLTypeSnapshot}s and the references to
+ * {...@link UserDefinedSQLType} upstream types need to be
updated.
+ */
+ public UpstreamTypeUpdaterListener(ArchitectSession session) {
+ this.session = session;
+ }
+
+ @Override
+ protected void childAddedImpl(SPChildEvent evt) {
+ if (evt.getChild() instanceof UserDefinedSQLTypeSnapshot) {
+ try {
+ UserDefinedSQLTypeSnapshot snapshot =
(UserDefinedSQLTypeSnapshot) evt.getChild();
+ if (!snapshot.isDomainSnapshot()) {
+ String originalUUID = snapshot.getOriginalUUID();
+ List<UserDefinedSQLType> types = new
ArrayList<UserDefinedSQLType>();
+ SQLDatabase targetDatabase =
session.getWorkspace().getTargetDatabase();
+ SQLObjectUtils.findDescendentsByClass(
+ targetDatabase,
+ UserDefinedSQLType.class,
+ types);
+ for (UserDefinedSQLType type : types) {
+ if (type.getUpstreamType() != null &&
+
type.getUpstreamType().getUUID().equals(originalUUID)) {
+ type.setUpstreamType(snapshot.getSPObject());
+ }
+ }
+ }
+ } catch (SQLObjectException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+}
=======================================
--- /trunk/src/main/java/ca/sqlpower/architect/ArchitectSessionImpl.java
Thu Jul 22 13:35:26 2010
+++ /trunk/src/main/java/ca/sqlpower/architect/ArchitectSessionImpl.java
Tue Jul 27 09:04:00 2010
@@ -27,6 +27,7 @@
import ca.sqlpower.architect.ddl.DDLGenerator;
import ca.sqlpower.architect.ddl.GenericDDLGenerator;
import ca.sqlpower.architect.enterprise.DomainCategory;
+import ca.sqlpower.architect.enterprise.UpstreamTypeUpdaterListener;
import ca.sqlpower.architect.profile.ProfileManager;
import ca.sqlpower.architect.profile.ProfileManagerImpl;
import ca.sqlpower.architect.swingui.LiquibaseSettings;
@@ -41,9 +42,9 @@
import ca.sqlpower.swingui.event.SessionLifecycleListener;
import ca.sqlpower.util.DefaultUserPrompterFactory;
import ca.sqlpower.util.UserPrompter;
-import ca.sqlpower.util.UserPrompterFactory;
import ca.sqlpower.util.UserPrompter.UserPromptOptions;
import ca.sqlpower.util.UserPrompter.UserPromptResponse;
+import ca.sqlpower.util.UserPrompterFactory;
/**
* The ArchitectSession class represents a single user's session with
@@ -106,7 +107,8 @@
} catch (SQLException e) {
throw new SQLObjectException("SQL Error in ddlGenerator",e);
}
-
+
+ project.addSPListener(new UpstreamTypeUpdaterListener(this));
}
// --------------- accessors and mutators ------------------
=======================================
---
/trunk/src/main/java/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java
Thu Jul 22 14:31:50 2010
+++
/trunk/src/main/java/ca/sqlpower/architect/enterprise/ArchitectClientSideSession.java
Tue Jul 27 09:04:00 2010
@@ -65,6 +65,7 @@
import ca.sqlpower.enterprise.client.RevisionController;
import ca.sqlpower.enterprise.client.SPServerInfo;
import ca.sqlpower.enterprise.client.User;
+import ca.sqlpower.object.SPObjectUUIDComparator;
import ca.sqlpower.sql.DataSourceCollection;
import ca.sqlpower.sql.DatabaseListChangeEvent;
import ca.sqlpower.sql.DatabaseListChangeListener;
@@ -973,8 +974,12 @@
// The following was my attempt to merge the snapshot and system
types lists together
// without making it O(mn), but the code is a bit lengthier than
I'd like, so perhaps
// the added complexity may not be worth it?
- List<UserDefinedSQLTypeSnapshot> typeSnapshots =
getWorkspace().getChildren(UserDefinedSQLTypeSnapshot.class);
- List<UserDefinedSQLType> systemTypes =
getSystemWorkspace().getChildren(UserDefinedSQLType.class);
+ List<UserDefinedSQLTypeSnapshot> typeSnapshots =
+ new ArrayList<UserDefinedSQLTypeSnapshot>(
+
getWorkspace().getChildren(UserDefinedSQLTypeSnapshot.class));
+ List<UserDefinedSQLType> systemTypes =
+ new ArrayList<UserDefinedSQLType>(
+
getSystemWorkspace().getChildren(UserDefinedSQLType.class));
// Remove domain snapshots from the list
for (int i = typeSnapshots.size() - 1; i >= 0; i--) {
@@ -993,11 +998,7 @@
return
o1.getOriginalUUID().compareTo(o2.getOriginalUUID());
}
});
- Collections.sort(systemTypes, new Comparator<UserDefinedSQLType>()
{
- public int compare(UserDefinedSQLType o1, UserDefinedSQLType
o2) {
- return o1.getUUID().compareTo(o2.getUUID());
- }
- });
+ Collections.sort(systemTypes, new
SPObjectUUIDComparator<UserDefinedSQLType>());
// Now go through the list of system types. If a snapshot type's
// original UUID matches, then replace the system type with the
snapshot.
@@ -1039,8 +1040,10 @@
// The following was my attempt to merge the snapshot and system
category lists together
// without making it O(nm), but the code is a bit lengthier than
I'd like, so perhaps
// the added complexity may not be worth it?
- List<DomainCategorySnapshot> categorySnapshots =
getWorkspace().getChildren(DomainCategorySnapshot.class);
- List<DomainCategory> systemCategories =
getSystemWorkspace().getChildren(DomainCategory.class);
+ List<DomainCategorySnapshot> categorySnapshots =
+ new
ArrayList<DomainCategorySnapshot>(getWorkspace().getChildren(DomainCategorySnapshot.class));
+ List<DomainCategory> systemCategories =
+ new
ArrayList<DomainCategory>(getSystemWorkspace().getChildren(DomainCategory.class));
// If there are no snapshots, just return the system categories.
if (categorySnapshots.size() == 0) return
Collections.unmodifiableList(systemCategories);
@@ -1051,11 +1054,7 @@
return
o1.getOriginalUUID().compareTo(o2.getOriginalUUID());
}
});
- Collections.sort(systemCategories, new
Comparator<DomainCategory>() {
- public int compare(DomainCategory o1, DomainCategory o2) {
- return o1.getUUID().compareTo(o2.getUUID());
- }
- });
+ Collections.sort(systemCategories, new
SPObjectUUIDComparator<DomainCategory>());
// Now go through the list of system categories. If a snapshot
category's
// original UUID matches, then replace the system category with
the snapshot.
@@ -1087,7 +1086,7 @@
return Collections.unmodifiableList(systemCategories);
}
-
+
@Override
public ArchitectSwingProject getWorkspace() {
return (ArchitectSwingProject) super.getWorkspace();
=======================================
---
/trunk/src/main/java/ca/sqlpower/architect/swingui/SQLTypeTreeModel.java
Thu Jul 22 14:31:50 2010
+++
/trunk/src/main/java/ca/sqlpower/architect/swingui/SQLTypeTreeModel.java
Tue Jul 27 09:04:00 2010
@@ -45,8 +45,6 @@
private static final Logger logger =
Logger.getLogger(SQLTypeTreeModel.class);
- private final ArchitectSession session;
-
/**
* This {...@link Comparator} can compare {...@link UserDefinedSQLType} and
* {...@link DomainCategory} objects. {...@link UserDefinedSQLType}s always
come
@@ -68,21 +66,54 @@
}
};
+ /**
+ * The {...@link ArchitectProject} that is the root of this tree.
+ */
+ private final ArchitectProject root;
+
+ /**
+ * The {...@link List} of {...@link UserDefinedSQLType}s reflective of the
types
+ * in the {...@link ArchitectProject} when the constructor of this tree
model
+ * is called. Types are not directly retrieved from the
+ * {...@link ArchitectProject} as it may have changed after creation of
this
+ * model.
+ */
+ private final List<UserDefinedSQLType> sqlTypes;
+
+ /**
+ * The {...@link List} of {...@link DomainCategory}s reflective of the
categories
+ * in the {...@link ArchitectProject} when the constructor of this tree
model
+ * is called. Categories are not directly retrieved from the
+ * {...@link ArchitectProject} as it may have changed after creation of
this
+ * model.
+ */
+ private final List<DomainCategory> domainCategories;
+
+ /**
+ * Creates a new SQLTypeTreeModel.
+ *
+ * @param session
+ * The {...@link ArchitectSession} to retrieve the
+ * {...@link ArchitectProject}, and its child
+ * {...@link UserDefinedSQLType}s and {...@link DomainCategory}s
from.
+ */
public SQLTypeTreeModel(ArchitectSession session) {
- this.session = session;
+ root = session.getWorkspace();
+ sqlTypes = new
ArrayList<UserDefinedSQLType>(session.getSQLTypes());
+ domainCategories = new
ArrayList<DomainCategory>(session.getDomainCategories());
}
public SPObject getChild(Object parent, int index) {
// If the parent is the delegate ArchitectProject, get the child at
// the specified index which should be of type UserDefinedSQLType
// or DomainCategory.
- if (session.getWorkspace() == parent) {
+ if (root == parent) {
return getChildren().get(index);
// If the parent is DomainCategory, get the child at the specified
// index which should be of type UserDefinedSQLType.
} else if (parent instanceof DomainCategory &&
- session.getDomainCategories().contains(parent)) {
+ domainCategories.contains(parent)) {
return getDomainTypes((DomainCategory) parent).get(index);
}
@@ -90,10 +121,10 @@
}
public int getChildCount(Object parent) {
- if (session.getWorkspace() == parent) {
+ if (root == parent) {
return getChildren().size();
} else if (parent instanceof DomainCategory &&
- session.getDomainCategories().contains(parent)) {
+ domainCategories.contains(parent)) {
return getDomainTypes((DomainCategory) parent).size();
}
return 0;
@@ -105,8 +136,8 @@
*/
private List<? extends SPObject> getChildren() {
List<SPObject> children = new ArrayList<SPObject>();
- children.addAll(session.getDomainCategories());
- children.addAll(session.getSQLTypes());
+ children.addAll(domainCategories);
+ children.addAll(sqlTypes);
Collections.sort(children, typeComparator);
return Collections.unmodifiableList(children);
}
@@ -121,19 +152,19 @@
* contained under the given {...@link DomainCategory}.
*/
private List<UserDefinedSQLType> getDomainTypes(DomainCategory
category) {
- List<UserDefinedSQLType> children = new
ArrayList<UserDefinedSQLType>();
- children.addAll(category.getChildren(UserDefinedSQLType.class));
+ List<UserDefinedSQLType> children = new
ArrayList<UserDefinedSQLType>(
+ category.getChildren(UserDefinedSQLType.class));
Collections.sort(children, typeComparator);
- return children;
+ return Collections.unmodifiableList(children);
}
public int getIndexOfChild(Object parent, Object child) {
if (parent == null || child == null) {
return -1;
- } else if (session.getWorkspace() == parent) {
+ } else if (root == parent) {
return getChildren().indexOf(child);
} else if (parent instanceof DomainCategory &&
- session.getDomainCategories().contains(parent)) {
+ domainCategories.contains(parent)) {
if (child instanceof UserDefinedSQLType) {
return getDomainTypes((DomainCategory)
parent).indexOf(child);
}
@@ -142,7 +173,7 @@
}
public ArchitectProject getRoot() {
- return session.getWorkspace();
+ return root;
}
public boolean isLeaf(Object node) {