You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ke...@apache.org on 2011/09/12 16:56:14 UTC
svn commit: r1169782 - in
/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql:
sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/
sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/
sql-tests-...
Author: kevin
Date: Mon Sep 12 14:56:13 2011
New Revision: 1169782
URL: http://svn.apache.org/viewvc?rev=1169782&view=rev
Log:
ISIS-118: Collections can now handle polymorphic types, including classes.
Added:
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyCollectionMapper.java
- copied, changed from r1169477, incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/CombinedCollectionMapper.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyInChildCollectionMapper.java
- copied, changed from r1169477, incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/MultiColumnCombinedCollectionMapper.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java (with props)
Modified:
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/CombinedCollectionMapper.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/MultiColumnCombinedCollectionMapper.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/JdbcAbstractReferenceFieldMapping.java
incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-tests-common/src/test/java/org/apache/isis/runtimes/dflt/objectstores/sql/PolymorphismTest.java
Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java?rev=1169782&r1=1169781&r2=1169782&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/AbstractAutoMapper.java Mon Sep 12 14:56:13 2011
@@ -82,10 +82,13 @@ public abstract class AbstractAutoMapper
private void setUpFieldMappers(final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup,
final String className, final String parameterBase) {
final IsisConfiguration configParameters = IsisContext.getConfiguration();
- table = configParameters.getString(parameterBase + "table");
+ table = configParameters.getString(parameterBase + ".table." + className);
if (table == null) {
- final String name = "isis_" + className.substring(className.lastIndexOf('.') + 1).toUpperCase();
- table = Sql.sqlName(name);
+ // final String name = "isis_" + className.substring(className.lastIndexOf('.') + 1);
+ final String name = getTableNameFromSpecification(specification);
+ table = name;
+ } else {
+ table = Sql.tableIdentifier(table);
}
dbCreatesId = configParameters.getBoolean(parameterBase + "db-ids", false);
@@ -95,11 +98,13 @@ public abstract class AbstractAutoMapper
// setupSpecifiedMapping(specification, configParameters, parameterBase);
}
- table = Sql.tableIdentifier(table);
-
LOG.info("table mapping: " + table + " (" + columnList() + ")");
}
+ protected String getTableNameFromSpecification(ObjectSpecification objectSpecification) {
+ return Sql.tableIdentifier(Sql.sqlName("isis_" + objectSpecification.getShortIdentifier()));
+ }
+
protected List<ObjectAssociation> fields = new ArrayList<ObjectAssociation>();
protected void getExtraFields(List<ObjectAssociation> fields) {
@@ -126,8 +131,6 @@ public abstract class AbstractAutoMapper
final ObjectAssociation[] oneToManyProperties = new ObjectAssociation[collectionFieldCount];
collectionMappers = new CollectionMapper[collectionFieldCount];
collectionMapperFields = new String[collectionFieldCount];
- // Properties collectionMappings = configParameters.getPropertiesStrippingPrefix(parameterBase +
- // "collection");
final IsisConfiguration subset = IsisContext.getConfiguration().createSubset(parameterBase + ".mapper.");
for (int i = 0, simpleFieldNo = 0, collectionFieldNo = 0; i < fields.size(); i++) {
@@ -137,24 +140,23 @@ public abstract class AbstractAutoMapper
} else if (field.isOneToManyAssociation()) {
oneToManyProperties[collectionFieldNo] = field;
- // TODO: Replace "new CombinedCollectionMapper" with a factory method(?) to allow a different
+ // TODO: Replace "new ForeignKeyCollectionMapper" with a factory method(?) to allow a different
// default CollectionMapper
final String type = subset.getString(field.getId());
if (type == null || type.equals("association-table")) {
// collectionMappers[collectionFieldNo] = new AutoCollectionMapper(specification,
// oneToManyProperties[collectionFieldNo], lookup);
// collectionMappers[collectionFieldNo] = new
- // CombinedCollectionMapper(oneToManyProperties[collectionFieldNo], parameterBase, lookup,
+ // ForeignKeyCollectionMapper(oneToManyProperties[collectionFieldNo], parameterBase, lookup,
// objectMapperLookup);
CollectionMapper collectionMapper = null;
// Trying to detect recursion, here.
- // Let MultiColumnCombinedCollectionMapper find itself when a field is a collection of the current
+ // Let ForeignKeyInChildCollectionMapper find itself when a field is a collection of the current
// field type.
- if (this instanceof MultiColumnCombinedCollectionMapper) {
- // TODO: Polymorphism - is it sufficient for the collectionMapper to handle the subclasses?
- MultiColumnCombinedCollectionMapper mc = (MultiColumnCombinedCollectionMapper) this;
+ if (this instanceof ForeignKeyInChildCollectionMapper) {
+ ForeignKeyInChildCollectionMapper mc = (ForeignKeyInChildCollectionMapper) this;
if (mc.priorField == field) {
collectionMapper = mc;
@@ -162,9 +164,17 @@ public abstract class AbstractAutoMapper
}
if (collectionMapper == null) {
- collectionMapper =
- new MultiColumnCombinedCollectionMapper(oneToManyProperties[collectionFieldNo],
- parameterBase, lookup, objectMapperLookup, this, field);
+ // TODO: Polymorphism - is it sufficient for the collectionMapper to handle the subclasses?
+ if (field.getSpecification().hasSubclasses()) {
+ collectionMapper =
+ new PolymorphicForeignKeyInChildCollectionMapper(
+ oneToManyProperties[collectionFieldNo], parameterBase, lookup, objectMapperLookup,
+ this, field);
+ } else {
+ collectionMapper =
+ new ForeignKeyInChildCollectionMapper(oneToManyProperties[collectionFieldNo],
+ parameterBase, lookup, objectMapperLookup, this, field);
+ }
}
collectionMappers[collectionFieldNo] = collectionMapper;
@@ -177,7 +187,7 @@ public abstract class AbstractAutoMapper
throw new SqlObjectStoreException("Expected property " + property);
}
/*
- * collectionMappers[collectionFieldNo] = new CombinedCollectionMapper(elementType,
+ * collectionMappers[collectionFieldNo] = new ForeignKeyCollectionMapper(elementType,
* oneToManyProperties[collectionFieldNo], parameterBase, lookup, objectMapperLookup);
*/
} else {
Copied: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyCollectionMapper.java (from r1169477, incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/CombinedCollectionMapper.java)
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyCollectionMapper.java?p2=incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyCollectionMapper.java&p1=incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/CombinedCollectionMapper.java&r1=1169477&r2=1169782&rev=1169782&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/CombinedCollectionMapper.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyCollectionMapper.java Mon Sep 12 14:56:13 2011
@@ -20,6 +20,7 @@
package org.apache.isis.runtimes.dflt.objectstores.sql.auto;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import org.apache.log4j.Logger;
@@ -44,8 +45,14 @@ import org.apache.isis.runtimes.dflt.obj
import org.apache.isis.runtimes.dflt.objectstores.sql.mapping.ObjectReferenceMapping;
import org.apache.isis.runtimes.dflt.runtime.persistence.PersistorUtil;
-public class CombinedCollectionMapper extends AbstractAutoMapper implements CollectionMapper {
- private static final Logger LOG = Logger.getLogger(CombinedCollectionMapper.class);
+/**
+ * Stores 1-to-many collections by creating a foreign-key column in the table for the incoming objectAssociation class.
+ * This assumes this the class is only ever in 1 collection parent.
+ *
+ * @version $Rev$ $Date$
+ */
+public class ForeignKeyCollectionMapper extends AbstractAutoMapper implements CollectionMapper {
+ private static final Logger LOG = Logger.getLogger(ForeignKeyCollectionMapper.class);
private final ObjectAssociation field;
private final IdMapping idMapping;
private final VersionMapping versionMapping;
@@ -55,16 +62,13 @@ public class CombinedCollectionMapper ex
private final ObjectMappingLookup objectMapperLookup2;
private ObjectMapping originalMapping = null;
- private final boolean isAbstract;
- public CombinedCollectionMapper(final ObjectAssociation objectAssociation, final String parameterBase,
+ public ForeignKeyCollectionMapper(final ObjectAssociation objectAssociation, final String parameterBase,
final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup) {
super(objectAssociation.getSpecification().getFullIdentifier(), parameterBase, lookup, objectMapperLookup);
this.field = objectAssociation;
- isAbstract = field.getSpecification().isAbstract();
-
objectMapperLookup2 = objectMapperLookup;
idMapping = lookup.createIdMapping();
@@ -74,7 +78,7 @@ public class CombinedCollectionMapper ex
foreignKeyName = Sql.sqlName("fk_" + getColumnName());
foreignKeyName = Sql.identifier(foreignKeyName);
- foreignKeyMapping = lookup.createMapping(columnName, objectAssociation.getSpecification());
+ foreignKeyMapping = lookup.createMapping(columnName, specification);
}
protected String determineColumnName(final ObjectAssociation objectAssociation) {
@@ -89,76 +93,67 @@ public class CombinedCollectionMapper ex
this.columnName = columnName;
}
- @Override
- public boolean needsTables(final DatabaseConnector connection) {
- return isAbstract || !connection.hasColumn(table, foreignKeyName);
+ protected String getForeignKeyName() {
+ return foreignKeyName;
}
@Override
public void startup(final DatabaseConnector connector, final FieldMappingLookup lookup) {
if (originalMapping == null) {
- originalMapping = objectMapperLookup.getMapping(field.getSpecification(), null);
+ originalMapping = objectMapperLookup.getMapping(specification, null);
}
originalMapping.startup(connector, objectMapperLookup2);
super.startup(connector, lookup);
}
@Override
+ public boolean needsTables(final DatabaseConnector connection) {
+ return !connection.hasColumn(table, foreignKeyName);
+ }
+
+ @Override
public void createTables(final DatabaseConnector connection) {
- if (isAbstract) {
- return;
- }
final StringBuffer sql = new StringBuffer();
sql.append("alter table ");
sql.append(table);
sql.append(" add ");
- foreignKeyMapping.appendColumnDefinitions(sql);
+ appendColumnDefinitions(sql);
connection.update(sql.toString());
}
+ protected void appendCollectionUpdateColumnsToNull(StringBuffer sql) {
+ sql.append(foreignKeyName + "=NULL ");
+ }
+
+ protected void appendCollectionWhereValues(final DatabaseConnector connector, final ObjectAdapter parent,
+ final StringBuffer sql) {
+ foreignKeyMapping.appendUpdateValues(connector, sql, parent);
+ }
+
+ protected void appendCollectionUpdateValues(final DatabaseConnector connector, final ObjectAdapter parent,
+ final StringBuffer sql) {
+ appendCollectionWhereValues(connector, parent, sql);
+ }
+
+ protected void appendColumnDefinitions(final StringBuffer sql) {
+ foreignKeyMapping.appendColumnDefinitions(sql);
+ }
+
@Override
public void loadInternalCollection(final DatabaseConnector connector, final ObjectAdapter parent,
final boolean makeResolved) {
- if (isAbstract) { // hasSubClasses, too?
- // TODO: Polymorphism: loadInternalCollection must load the instance from all the possible child tables.
- LOG.debug("Is Abstract");
- return;
- }
-
final ObjectAdapter collection = field.get(parent);
if (collection.getResolveState().canChangeTo(ResolveState.RESOLVING)) {
LOG.debug("loading internal collection " + field);
PersistorUtil.start(collection, ResolveState.RESOLVING);
- final StringBuffer sql = new StringBuffer();
- sql.append("select ");
- idMapping.appendColumnNames(sql);
+ final List<ObjectAdapter> list = new ArrayList<ObjectAdapter>();
- sql.append(", ");
- final String columnList = columnList();
- if (columnList.length() > 0) {
- sql.append(columnList);
- sql.append(", ");
- }
- sql.append(versionMapping.appendSelectColumns());
- sql.append(" from ");
- sql.append(table);
- sql.append(" where ");
- foreignKeyMapping.appendUpdateValues(connector, sql, parent);
+ loadCollectionIntoList(connector, parent, makeResolved, list);
- final Results rs = connector.select(sql.toString());
- final List<ObjectAdapter> list = new ArrayList<ObjectAdapter>();
- while (rs.next()) {
- final Oid oid = idMapping.recreateOid(rs, specification);
- final ObjectAdapter element = getAdapter(specification, oid);
- loadFields(element, rs, makeResolved);
- LOG.debug(" element " + element.getOid());
- list.add(element);
- }
final CollectionFacet collectionFacet = collection.getSpecification().getFacet(CollectionFacet.class);
collectionFacet.init(collection, list.toArray(new ObjectAdapter[list.size()]));
- rs.close();
PersistorUtil.end(collection);
// TODO: Need to finalise this behaviour. At the moment, all collections will get infinitely resolved. I
@@ -174,6 +169,35 @@ public class CombinedCollectionMapper ex
}
}
+ protected void loadCollectionIntoList(final DatabaseConnector connector, final ObjectAdapter parent,
+ final boolean makeResolved, final List<ObjectAdapter> list) {
+ final StringBuffer sql = new StringBuffer();
+ sql.append("select ");
+ idMapping.appendColumnNames(sql);
+
+ sql.append(", ");
+ final String columnList = columnList();
+ if (columnList.length() > 0) {
+ sql.append(columnList);
+ sql.append(", ");
+ }
+ sql.append(versionMapping.appendSelectColumns());
+ sql.append(" from ");
+ sql.append(table);
+ sql.append(" where ");
+ appendCollectionWhereValues(connector, parent, sql);
+
+ final Results rs = connector.select(sql.toString());
+ while (rs.next()) {
+ final Oid oid = idMapping.recreateOid(rs, specification);
+ final ObjectAdapter element = getAdapter(specification, oid);
+ loadFields(element, rs, makeResolved);
+ LOG.debug(" element " + element.getOid());
+ list.add(element);
+ }
+ rs.close();
+ }
+
protected void loadFields(final ObjectAdapter object, final Results rs, final boolean makeResolved) {
if (object.getResolveState().canChangeTo(ResolveState.RESOLVING)) {
PersistorUtil.start(object, ResolveState.RESOLVING);
@@ -187,24 +211,30 @@ public class CombinedCollectionMapper ex
}
}
+ /**
+ * Override this in the Polymorphic case to return just the elements that are appropriate for the subclass currently
+ * being handled.
+ *
+ * @param collection
+ * @return those elements that ought to be used.
+ */
+ protected Iterator<ObjectAdapter> getElementsForCollectionAsIterator(final ObjectAdapter collection) {
+ final CollectionFacet collectionFacet = collection.getSpecification().getFacet(CollectionFacet.class);
+ final Iterable<ObjectAdapter> elements = collectionFacet.iterable(collection);
+ return elements.iterator();
+ }
+
@Override
public void saveInternalCollection(final DatabaseConnector connector, final ObjectAdapter parent) {
final ObjectAdapter collection = field.get(parent);
LOG.debug("Saving internal collection " + collection);
- final CollectionFacet collectionFacet = collection.getSpecification().getFacet(CollectionFacet.class);
- final Iterable<ObjectAdapter> elements = collectionFacet.iterable(collection);
+ final Iterator<ObjectAdapter> elements = getElementsForCollectionAsIterator(collection);
// TODO What is needed to allow a collection update (add/remove) to mark the collection as dirty?
// checkIfDirty(collection);
- if (elements.iterator().hasNext() == false) {
- return;
- }
-
- if (isAbstract) {
- // TODO: Polymorphism: saveInternalCollection must save instance into the appropriate child tables.
- LOG.debug("Is Abstract");
+ if (elements.hasNext() == false) {
return;
}
@@ -214,9 +244,9 @@ public class CombinedCollectionMapper ex
sql.append("update ");
sql.append(table);
sql.append(" set ");
- sql.append(foreignKeyName);
- sql.append(" = NULL where ");
- foreignKeyMapping.appendUpdateValues(connector, sql, parent);
+ appendCollectionUpdateColumnsToNull(sql);
+ sql.append(" where ");
+ appendCollectionWhereValues(connector, parent, sql);
connector.update(sql.toString());
// Reinstall collection parent
@@ -225,8 +255,7 @@ public class CombinedCollectionMapper ex
update.append("update ");
update.append(table);
update.append(" set ");
-
- foreignKeyMapping.appendUpdateValues(connector, update, parent);
+ appendCollectionUpdateValues(connector, parent, update);
update.append(" where ");
idMapping.appendColumnNames(update);
@@ -234,7 +263,9 @@ public class CombinedCollectionMapper ex
update.append(" IN (");
int count = 0;
- for (final ObjectAdapter element : elements) {
+ for (Iterator<ObjectAdapter> iterator = elements; iterator.hasNext();) {
+ ObjectAdapter element = iterator.next();
+
if (count++ > 0) {
update.append(",");
}
Copied: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyInChildCollectionMapper.java (from r1169477, incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/MultiColumnCombinedCollectionMapper.java)
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyInChildCollectionMapper.java?p2=incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyInChildCollectionMapper.java&p1=incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/MultiColumnCombinedCollectionMapper.java&r1=1169477&r2=1169782&rev=1169782&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/MultiColumnCombinedCollectionMapper.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/ForeignKeyInChildCollectionMapper.java Mon Sep 12 14:56:13 2011
@@ -38,12 +38,12 @@ import org.apache.isis.runtimes.dflt.obj
*
* @author Kevin
*/
-public class MultiColumnCombinedCollectionMapper extends CombinedCollectionMapper {
- private static final Logger LOG = Logger.getLogger(CombinedCollectionMapper.class);
+public class ForeignKeyInChildCollectionMapper extends ForeignKeyCollectionMapper {
+ private static final Logger LOG = Logger.getLogger(ForeignKeyCollectionMapper.class);
// TODO: Needs to detect if field has subclasses, and to add FK_* column to *all* non-abstract subclasses.
- public MultiColumnCombinedCollectionMapper(final ObjectAssociation objectAssociation, final String parameterBase,
+ public ForeignKeyInChildCollectionMapper(final ObjectAssociation objectAssociation, final String parameterBase,
final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup,
AbstractAutoMapper abstractAutoMapper, ObjectAssociation field) {
super(objectAssociation, parameterBase, lookup, objectMapperLookup);
Added: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java?rev=1169782&view=auto
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java (added)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java Mon Sep 12 14:56:13 2011
@@ -0,0 +1,218 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ *
+ */
+package org.apache.isis.runtimes.dflt.objectstores.sql.auto;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
+import org.apache.isis.runtimes.dflt.objectstores.sql.DatabaseConnector;
+import org.apache.isis.runtimes.dflt.objectstores.sql.FieldMappingLookup;
+import org.apache.isis.runtimes.dflt.objectstores.sql.ObjectMappingLookup;
+
+/**
+ * Used to map 1-to-many collections by creating, in the child table, 1 column per parent collection. The column is
+ * named by combining the final part of the parent class name and the collection variable name.
+ *
+ * @author Kevin
+ */
+public class PolymorphicForeignKeyInChildCollectionMapper extends ForeignKeyInChildCollectionMapper {
+
+ private static final Logger LOG = Logger.getLogger(PolymorphicForeignKeyInChildCollectionMapper.class);
+
+ // TODO: Fields have subclasses. Must add FK_* column to *all* non-abstract subclasses.
+ private final ObjectAssociation baseField;
+ private final List<String> tables;
+ private final List<ObjectSpecification> tableSpecifications;
+ // private final String classColumnName;
+
+ // For iterating through the subclasses
+ private ObjectSpecification currentTableSpecification;
+ private Iterator<ObjectAdapter> currentIterator;
+ private List<ObjectAdapter> currentCollection;
+ private int currentIndexStart;
+ private int currentIndex;
+
+ public PolymorphicForeignKeyInChildCollectionMapper(final ObjectAssociation objectAssociation,
+ final String parameterBase, final FieldMappingLookup lookup, final ObjectMappingLookup objectMapperLookup,
+ AbstractAutoMapper abstractAutoMapper, ObjectAssociation field) {
+ super(objectAssociation, parameterBase, lookup, objectMapperLookup, abstractAutoMapper, field);
+
+ this.baseField = objectAssociation;
+ // classColumnName = Sql.identifier(getForeignKeyName() + "_cls");
+
+ tables = new ArrayList<String>();
+ tableSpecifications = new ArrayList<ObjectSpecification>();
+ addSubSpecificationsToTable(specification);
+
+ }
+
+ protected void addSubSpecificationsToTable(ObjectSpecification objectSpecification) {
+ for (ObjectSpecification subSpecification : objectSpecification.subclasses()) {
+ if (subSpecification.isAbstract() == false) {
+ final String tableNameFromSpecification = getTableNameFromSpecification(subSpecification);
+ tables.add(tableNameFromSpecification);
+ tableSpecifications.add(subSpecification);
+ }
+ if (subSpecification.hasSubclasses()) {
+ addSubSpecificationsToTable(subSpecification);
+ }
+ }
+ }
+
+ @Override
+ public boolean needsTables(DatabaseConnector connection) {
+ for (String subTableName : tables) {
+ table = subTableName;
+ if (super.needsTables(connection)) { // || !connection.hasColumn(table, classColumnName)) {
+ // Stop on first table that is needed.
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void createTables(final DatabaseConnector connection) {
+ for (String subTableName : tables) {
+ table = subTableName;
+ if (super.needsTables(connection)) {
+ super.createTables(connection);
+ }
+
+ // if (!connection.hasColumn(table, classColumnName)) {
+ // // I couldn't combine this in one operation with appendColumnDefinitions
+ // final StringBuffer sql = new StringBuffer();
+ // sql.append("alter table ");
+ // sql.append(table);
+ // sql.append(" add ");
+ //
+ // sql.append(classColumnName);
+ // sql.append(" ");
+ // sql.append(JdbcConnector.TYPE_LONG_STRING());
+ //
+ // connection.update(sql.toString());
+ // }
+ }
+ }
+
+ @Override
+ protected void appendCollectionUpdateColumnsToNull(StringBuffer sql) {
+ super.appendCollectionUpdateColumnsToNull(sql);
+ // sql.append("," + classColumnName + "=NULL");
+ }
+
+ @Override
+ protected void appendCollectionUpdateValues(final DatabaseConnector connector, final ObjectAdapter parent,
+ final StringBuffer sql) {
+ super.appendCollectionUpdateValues(connector, parent, sql);
+ // sql.append("," + classColumnName + "=?");
+ // connector.addToQueryValues(currentTableSpecification.getFullIdentifier());
+ }
+
+ @Override
+ protected Iterator<ObjectAdapter> getElementsForCollectionAsIterator(final ObjectAdapter collection) {
+ return currentIterator;
+ }
+
+ @Override
+ public void saveInternalCollection(final DatabaseConnector connector, final ObjectAdapter parent) {
+ final ObjectAdapter collection = baseField.get(parent);
+ LOG.debug("Saving polymorphic internal collection " + collection);
+
+ currentCollection = new ArrayList<ObjectAdapter>();
+ currentIterator = super.getElementsForCollectionAsIterator(collection);
+ for (; currentIterator.hasNext();) {
+ ObjectAdapter item = currentIterator.next();
+ currentCollection.add(item);
+ }
+
+ // TODO: Polymorphism: save instances to appropriate subclass tables
+ for (int i = 0; i < tables.size(); i++) {
+ currentTableSpecification = tableSpecifications.get(i);
+ currentIndex = 0;
+ currentIndexStart = 0;
+
+ currentIterator = new Iterator<ObjectAdapter>() {
+ @Override
+ public boolean hasNext() {
+ for (int i = currentIndexStart; i < currentCollection.size(); i++) {
+ ObjectAdapter thisObjectAdapter = currentCollection.get(i);
+ if (thisObjectAdapter.getSpecification().isOfType(currentTableSpecification)) {
+ currentIndexStart = currentIndex = i;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public ObjectAdapter next() {
+ currentIndexStart = currentIndex + 1;
+ return currentCollection.get(currentIndex);
+ }
+
+ @Override
+ public void remove() {
+ }
+ };
+
+ // Provide replacement table and column definitions here
+ table = tables.get(i);
+ super.saveInternalCollection(connector, parent);
+ }
+ }
+
+ @Override
+ public void loadInternalCollection(final DatabaseConnector connector, final ObjectAdapter parent,
+ final boolean makeResolved) {
+ final ObjectAdapter collection = baseField.get(parent);
+ LOG.debug("loading polymorphic internal collection " + collection);
+ // TODO: Polymorphism: load instances from all subclass tables
+ super.loadInternalCollection(connector, parent, makeResolved);
+ }
+
+ @Override
+ protected void loadCollectionIntoList(final DatabaseConnector connector, final ObjectAdapter parent,
+ final boolean makeResolved, final List<ObjectAdapter> superList) {
+ // TODO: Polymorphism: save instances to appropriate subclass tables
+ final List<ObjectAdapter> list = new ArrayList<ObjectAdapter>();
+ for (int i = 0; i < tables.size(); i++) {
+ currentTableSpecification = tableSpecifications.get(i);
+ specification = currentTableSpecification;
+
+ table = tables.get(i);
+ super.loadCollectionIntoList(connector, parent, makeResolved, list);
+
+ superList.addAll(list);
+ list.clear();
+ }
+
+ }
+
+}
Propchange: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/auto/PolymorphicForeignKeyInChildCollectionMapper.java
------------------------------------------------------------------------------
svn:executable = *
Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/JdbcAbstractReferenceFieldMapping.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/JdbcAbstractReferenceFieldMapping.java?rev=1169782&r1=1169781&r2=1169782&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/JdbcAbstractReferenceFieldMapping.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-impl/src/main/java/org/apache/isis/runtimes/dflt/objectstores/sql/jdbc/JdbcAbstractReferenceFieldMapping.java Mon Sep 12 14:56:13 2011
@@ -65,7 +65,7 @@ public class JdbcAbstractReferenceFieldM
sql.append(", ");
sql.append(classnameColumn);
sql.append(" ");
- sql.append(JdbcConnector.TYPE_STRING());
+ sql.append(JdbcConnector.TYPE_LONG_STRING());
}
@Override
@@ -73,7 +73,7 @@ public class JdbcAbstractReferenceFieldM
super.appendCreateColumnDefinitions(sql);
sql.append(classnameColumn);
sql.append(" ");
- sql.append(JdbcConnector.TYPE_STRING());
+ sql.append(JdbcConnector.TYPE_LONG_STRING());
}
@Override
Modified: incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-tests-common/src/test/java/org/apache/isis/runtimes/dflt/objectstores/sql/PolymorphismTest.java
URL: http://svn.apache.org/viewvc/incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-tests-common/src/test/java/org/apache/isis/runtimes/dflt/objectstores/sql/PolymorphismTest.java?rev=1169782&r1=1169781&r2=1169782&view=diff
==============================================================================
--- incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-tests-common/src/test/java/org/apache/isis/runtimes/dflt/objectstores/sql/PolymorphismTest.java (original)
+++ incubator/isis/trunk/framework/runtimes/dflt/objectstores/sql/sql-tests-common/src/test/java/org/apache/isis/runtimes/dflt/objectstores/sql/PolymorphismTest.java Mon Sep 12 14:56:13 2011
@@ -170,7 +170,7 @@ public class PolymorphismTest extends Sq
List<PolyBaseClass> polyBaseClasses = polyTestClass.getPolyBaseClasses();
// TODO Polymorphism test temporary disabled
- // assertEquals(3, polyBaseClasses.size());
+ assertEquals(3, polyBaseClasses.size());
}