Author: ppoddar
Date: Fri Aug 29 10:46:15 2008
New Revision: 690346
URL: http://svn.apache.org/viewvc?rev=690346&view=rev
Log:
OPENJPA-697: Add new capabilities to support version columns to spread across
primary and secondary tables
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnSecondaryVersionPC.java
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionMappingInfo.java
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/VersionColumn.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnVersionPC.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestMultiColumnVersion.java
openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java
(original)
+++
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingInfo.java
Fri Aug 29 10:46:15 2008
@@ -95,6 +95,21 @@
public List getColumns() {
return (_cols == null) ? Collections.EMPTY_LIST : _cols;
}
+
+ /**
+ * Gets the columns whose table name matches the given table name.
+ */
+ public List getColumns(String tableName) {
+ if (_cols == null)
+ return Collections.EMPTY_LIST;
+ List result = new ArrayList();
+ for (Object col : _cols) {
+ if (StringUtils.equals(((Column)col).getTableName(),
+ tableName))
+ result.add(col);
+ }
+ return result;
+ }
/**
* Raw column data.
@@ -531,10 +546,19 @@
boolean fill = ((MappingRepository) context.getRepository()).
getMappingDefaults().defaultMissingInfo();
if ((!given.isEmpty() || (!adapt && !fill))
- && given.size() != tmplates.length)
- throw new MetaDataException(_loc.get(prefix + "-num-cols",
- context, String.valueOf(tmplates.length),
- String.valueOf(given.size())));
+ && given.size() != tmplates.length) {
+ // also consider when this info has columns from multiple tables
+ given = getColumns(table.getName());
+ if ((!adapt && !fill) && given.size() != tmplates.length) {
+ // try default table
+ given = getColumns("");
+ if ((!adapt && !fill) && given.size() != tmplates.length) {
+ throw new MetaDataException(_loc.get(prefix +
"-num-cols",
+ context, String.valueOf(tmplates.length),
+ String.valueOf(given.size())));
+ }
+ }
+ }
Column[] cols = new Column[tmplates.length];
_io = null;
@@ -547,6 +571,11 @@
}
return cols;
}
+
+ boolean canMerge(List given, Column[] templates, boolean adapt, boolean
fill) {
+ return !((!given.isEmpty() || (!adapt && !fill))
+ && given.size() != templates.length);
+ }
/**
* Set the proper internal column I/O metadata for the given column's
flags.
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionMappingInfo.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionMappingInfo.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionMappingInfo.java
(original)
+++
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/VersionMappingInfo.java
Fri Aug 29 10:46:15 2008
@@ -18,12 +18,23 @@
*/
package org.apache.openjpa.jdbc.meta;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.jdbc.meta.strats.NoneVersionStrategy;
import org.apache.openjpa.jdbc.meta.strats.SuperclassVersionStrategy;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.Index;
import org.apache.openjpa.jdbc.schema.SchemaGroup;
import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.UserException;
/**
* Information about the mapping from a version indicator to the schema, in
@@ -36,17 +47,59 @@
public class VersionMappingInfo
extends MappingInfo {
+ private static final Localizer _loc = Localizer.forPackage
+ (VersionMappingInfo.class);
/**
* Return the columns set for this version, based on the given templates.
*/
- public Column[] getColumns(Version version, Column[] tmplates,
+ public Column[] getColumns(Version version, Column[] templates,
boolean adapt) {
- Table table = version.getClassMapping().getTable();
+ if (spansMultipleTables(templates))
+ return getMultiTableColumns(version, templates, adapt);
+ Table table = getSingleTable(version, templates);
version.getMappingRepository().getMappingDefaults().populateColumns
- (version, table, tmplates);
- return createColumns(version, null, tmplates, table, adapt);
+ (version, table, templates);
+ return createColumns(version, null, templates, table, adapt);
}
-
+
+ /**
+ * Return the columns set for this version when the columns are spread
+ * across multiple tables.
+ */
+ public Column[] getMultiTableColumns(Version vers, Column[] templates,
+ boolean adapt) {
+ Table primaryTable = vers.getClassMapping().getTable();
+ List<String> secondaryTableNames = Arrays.asList(vers
+ .getClassMapping().getMappingInfo().getSecondaryTableNames());
+ Map<Table, List<Column>> assign = new HashMap<Table, List<Column>>();
+ for (Column col : templates) {
+ String tableName = col.getTableName();
+ Table table;
+ if (StringUtils.isEmpty(tableName)
+ || tableName.equals(primaryTable.getName())) {
+ table = primaryTable;
+ } else if (secondaryTableNames.contains(tableName)) {
+ table = primaryTable.getSchema().getTable(tableName);
+ } else {
+ throw new
UserException(_loc.get("bad-version-column-table",
+ col.getName(), tableName));
+ }
+ if (!assign.containsKey(table))
+ assign.put(table, new ArrayList<Column>());
+ assign.get(table).add(col);
+ }
+ MappingDefaults def = vers.getMappingRepository().getMappingDefaults();
+ List<Column> result = new ArrayList<Column>();
+ for (Table table : assign.keySet()) {
+ List<Column> cols = assign.get(table);
+ Column[] partTemplates = cols.toArray(new Column[cols.size()]);
+ def.populateColumns(vers, table, partTemplates);
+ result.addAll(Arrays.asList(createColumns(vers, null,
partTemplates,
+ table, adapt)));
+ }
+ return result.toArray(new Column[result.size()]);
+ }
+
/**
* Return the index to set on the version columns, or null if none.
*/
@@ -86,4 +139,30 @@
&& cls.getJoinablePCSuperclassMapping() == null))
setStrategy(strat);
}
+
+ /**
+ * Affirms if the given columns belong to more than one tables.
+ */
+ boolean spansMultipleTables(Column[] cols) {
+ if (cols == null || cols.length <= 1)
+ return false;
+ Set<String> tables = new HashSet<String>();
+ for (Column col : cols)
+ if (tables.add(col.getTableName()) && tables.size() > 1)
+ return true;
+ return false;
+ }
+
+ /**
+ * Gets the table where this version columns are mapped.
+ */
+ private Table getSingleTable(Version version, Column[] cols) {
+ if (cols == null || cols.length == 0
+ || StringUtils.isEmpty(cols[0].getTableName()))
+ return version.getClassMapping().getTable();
+ return version.getClassMapping().getTable().getSchema()
+ .getTable(cols[0].getTableName());
+ }
+
+
}
Modified:
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java
(original)
+++
openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ColumnVersionStrategy.java
Fri Aug 29 10:46:15 2008
@@ -31,6 +31,7 @@
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.schema.ColumnIO;
import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.Table;
import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.Row;
import org.apache.openjpa.jdbc.sql.RowManager;
@@ -48,6 +49,7 @@
* Uses a single column and corresponding version object.
*
* @author Marc Prud'hommeaux
+ * @author Pinaki Poddar
*/
public abstract class ColumnVersionStrategy
extends AbstractVersionStrategy {
@@ -110,19 +112,23 @@
/**
* Compare each element of the given arrays that must be of equal size.
*
- * @return If each element comparison results into same sign then
returns
- * that sign. If some elements compare equal and all the rest has the
same
- * sign then return that sign. Otherwise, return 1.
+ * @return If any element of a1 is later than corresponding element of
+ * a2 then return 1 i.e. a1 as a whole is later than a2.
+ * If each element of a1 is to equal corresponding element of a2 then
return
+ * 0 i.e. a1 is as a whole equals to a2.
+ * else return a negative number i.e. a1 is earlier than a2.
*/
protected int compare(Object[] a1, Object[] a2) {
if (a1.length != a2.length)
throw new InternalException();
- Set<Integer> comps = new HashSet<Integer>();
- for (int i = 0; i < a1.length; i++)
- comps.add(sign(compare(a1[i], a2[i])));
- if (comps.size() == 1 || (comps.size() == 2 && comps.remove(0)))
- return comps.iterator().next();
- return 1;
+ int total = 0;
+ for (int i = 0; i < a1.length; i++) {
+ int c = compare(a1[i], a2[i]);
+ if (c > 0)
+ return 1;
+ total += c;
+ }
+ return total;
}
int sign(int i) {
@@ -144,11 +150,12 @@
for (int i = 0; i < info.getColumns().size(); i++) {
templates[i] = new Column();
Column infoColumn = (Column)info.getColumns().get(i);
+ templates[i].setTableName(infoColumn.getTableName());
templates[i].setType(infoColumn.getType());
templates[i].setSize(infoColumn.getSize());
templates[i].setDecimalDigits(infoColumn.getDecimalDigits());
templates[i].setJavaType(getJavaType(i));
- templates[i].setName("versn" +i);
+ templates[i].setName(infoColumn.getName());
}
Column[] cols = info.getColumns(vers, templates, adapt);
for (int i = 0; i < cols.length; i++)
@@ -175,12 +182,11 @@
Column[] cols = vers.getColumns();
ColumnIO io = vers.getColumnIO();
Object initial = nextVersion(null);
- Row row = rm.getRow(vers.getClassMapping().getTable(),
- Row.ACTION_INSERT, sm, true);
- for (int i = 0; i < cols.length; i++)
+ for (int i = 0; i < cols.length; i++) {
+ Row row = rm.getRow(cols[i].getTable(), Row.ACTION_INSERT, sm,
true);
if (io.isInsertable(i, initial == null))
row.setObject(cols[i], getColumnValue(initial, i));
-
+ }
// set initial version into state manager
Object nextVersion;
nextVersion = initial;
@@ -197,12 +203,11 @@
Object curVersion = sm.getVersion();
Object nextVersion = nextVersion(curVersion);
- Row row = rm.getRow(vers.getClassMapping().getTable(),
- Row.ACTION_UPDATE, sm, true);
- row.setFailedObject(sm.getManagedInstance());
// set where and update conditions on row
for (int i = 0; i < cols.length; i++) {
+ Row row = rm.getRow(cols[i].getTable(), Row.ACTION_UPDATE, sm,
true);
+ row.setFailedObject(sm.getManagedInstance());
if (curVersion != null && sm.isVersionCheckRequired())
row.whereObject(cols[i], getColumnValue(curVersion, i));
if (vers.getColumnIO().isUpdatable(i, nextVersion == null))
@@ -215,14 +220,14 @@
public void delete(OpenJPAStateManager sm, JDBCStore store, RowManager rm)
throws SQLException {
- Row row = rm.getRow(vers.getClassMapping().getTable(),
- Row.ACTION_DELETE, sm, true);
- row.setFailedObject(sm.getManagedInstance());
Column[] cols = vers.getColumns();
Object curVersion = sm.getVersion();
Object cur;
for (int i = 0; i < cols.length; i++) {
+ Row row = rm.getRow(cols[i].getTable(),
+ Row.ACTION_DELETE, sm, true);
+ row.setFailedObject(sm.getManagedInstance());
cur = getColumnValue(curVersion, i);
// set where and update conditions on row
if (cur != null)
Modified:
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
(original)
+++
openjpa/trunk/openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/localizer.properties
Fri Aug 29 10:46:15 2008
@@ -414,4 +414,6 @@
table "{2}" can not be found in the list of available columns "{3}".
unique-no-table: A unique constraint on table "{0}" can not be added to \
mapping of class "{1}" because the table does neither match its primary
\
- table "{2}" nor any of its secondary table(s) "{3}".
\ No newline at end of file
+ table "{2}" nor any of its secondary table(s) "{3}".
+bad-version-column-table: One of the version column "{0}" has been associated \
+ with table "{1}", but no primary or secondary table of such name exists.
\ No newline at end of file
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
(original)
+++
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/AnnotationPersistenceMappingParser.java
Fri Aug 29 10:46:15 2008
@@ -807,6 +807,7 @@
*/
private static Column newColumn(VersionColumn anno) {
Column col = new Column();
+ col.setTableName(anno.table());
if (!StringUtils.isEmpty(anno.name()))
col.setName(anno.name());
if (anno.precision() != 0)
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/VersionColumn.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/VersionColumn.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/VersionColumn.java
(original)
+++
openjpa/trunk/openjpa-persistence-jdbc/src/main/java/org/apache/openjpa/persistence/jdbc/VersionColumn.java
Fri Aug 29 10:46:15 2008
@@ -49,4 +49,6 @@
int precision() default 0; // decimal precision
int scale() default 0; // decimal scale
+
+ String table() default "";
}
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnSecondaryVersionPC.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnSecondaryVersionPC.java?rev=690346&view=auto
==============================================================================
---
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnSecondaryVersionPC.java
(added)
+++
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnSecondaryVersionPC.java
Fri Aug 29 10:46:15 2008
@@ -0,0 +1,95 @@
+/*
+ * 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.openjpa.persistence.jdbc.annotations;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.PrimaryKeyJoinColumn;
+import javax.persistence.SecondaryTable;
+import javax.persistence.SecondaryTables;
+import javax.persistence.Table;
+
+import org.apache.openjpa.persistence.jdbc.VersionColumn;
+import org.apache.openjpa.persistence.jdbc.VersionColumns;
+import org.apache.openjpa.persistence.jdbc.VersionStrategy;
+
+/**
+ * Persistent entity for testing multiple column numeric version strategy as
set
+ * by <code>@VersionColumns</code> annotations and where the version columns
are
+ * spread over primary and secondary table(s).
+ *
+ * @author Pinaki Poddar
+ *
+ */
[EMAIL PROTECTED]
[EMAIL PROTECTED](name="MCSV")
[EMAIL PROTECTED]({
+ @SecondaryTable(name = "MCSV1", [EMAIL PROTECTED](name="ID")),
+ @SecondaryTable(name = "MCSV2", [EMAIL PROTECTED](name="ID"))
+})
[EMAIL PROTECTED]("version-numbers")
[EMAIL PROTECTED]({
+ @VersionColumn(name = "v11", table="MCSV1"),
+ @VersionColumn(name = "v12", table="MCSV1"),
+ @VersionColumn(name = "v21", table="MCSV2"),
+ @VersionColumn(name = "v01") // default is the primary table
+})
+public class MultiColumnSecondaryVersionPC {
+ @Id
+ @GeneratedValue
+ private long id;
+
+ private String name;
+
+ @Column(table="MCSV1")
+ private String s1;
+
+ @Column(table="MCSV2")
+ private String s2;
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getS1() {
+ return s1;
+ }
+
+ public void setS1(String s1) {
+ this.s1 = s1;
+ }
+
+ public String getS2() {
+ return s2;
+ }
+
+ public void setS2(String s2) {
+ this.s2 = s2;
+ }
+}
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnVersionPC.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnVersionPC.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnVersionPC.java
(original)
+++
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/MultiColumnVersionPC.java
Fri Aug 29 10:46:15 2008
@@ -21,6 +21,7 @@
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
+import javax.persistence.Table;
import org.apache.openjpa.persistence.jdbc.VersionColumn;
import org.apache.openjpa.persistence.jdbc.VersionColumns;
@@ -36,6 +37,7 @@
*
*/
@Entity
[EMAIL PROTECTED](name="MCV")
@VersionStrategy("version-numbers")
@VersionColumns({
@VersionColumn(name="v1"),
Modified:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestMultiColumnVersion.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestMultiColumnVersion.java?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
---
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestMultiColumnVersion.java
(original)
+++
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/annotations/TestMultiColumnVersion.java
Fri Aug 29 10:46:15 2008
@@ -19,7 +19,6 @@
package org.apache.openjpa.persistence.jdbc.annotations;
import java.lang.reflect.Array;
-import java.util.Arrays;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.strats.MultiColumnVersionStrategy;
@@ -27,23 +26,30 @@
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
/**
- * Tests numeric version spanning multiple columns.
+ * Tests numeric version spanning multiple columns and those columns spanning
+ * multiple tables.
*
* @author Pinaki Poddar
*/
public class TestMultiColumnVersion extends SingleEMFTestCase {
public void setUp() {
- setUp(MultiColumnVersionPC.class, CLEAR_TABLES);
+ setUp(MultiColumnVersionPC.class, MultiColumnSecondaryVersionPC.class,
+ CLEAR_TABLES);
}
public void testVersionStrategyIsSet() {
- ClassMapping mapping = getMapping(MultiColumnVersionPC.class);
+ assertStrategy(MultiColumnVersionPC.class);
+ assertStrategy(MultiColumnSecondaryVersionPC.class);
+ }
+
+ public void assertStrategy(Class cls) {
+ ClassMapping mapping = getMapping(cls);
assertNotNull(mapping.getVersion());
assertTrue(mapping.getVersion().getStrategy()
instanceof MultiColumnVersionStrategy);
}
- public void testVersionOnPersistAndUpdate() {
+ public void testVersionOnPersistAndUpdateForSingleTable() {
OpenJPAEntityManager em = emf.createEntityManager();
em.getTransaction().begin();
MultiColumnVersionPC pc = new MultiColumnVersionPC();
@@ -59,7 +65,7 @@
assertVersionEquals(new Number[]{2,2, 2.0f}, em.getVersion(pc));
}
- public void testConcurrentOptimisticUpdateFails() {
+ public void testConcurrentOptimisticUpdateFailsForSingleTable() {
OpenJPAEntityManager em1 = emf.createEntityManager();
em1.getTransaction().begin();
OpenJPAEntityManager em2 = emf.createEntityManager();
@@ -88,7 +94,7 @@
}
}
- public void testConcurrentOptimisticReadSucceeds() {
+ public void testConcurrentOptimisticReadSucceedsForSingleTable() {
OpenJPAEntityManager em1 = emf.createEntityManager();
em1.getTransaction().begin();
OpenJPAEntityManager em2 = emf.createEntityManager();
@@ -108,6 +114,71 @@
em2.getTransaction().commit();
}
+ public void testVersionOnPersistAndUpdateForMultiTable() {
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ MultiColumnSecondaryVersionPC pc = new MultiColumnSecondaryVersionPC();
+ assertEquals(null, em.getVersion(pc));
+ em.persist(pc);
+ em.getTransaction().commit();
+ assertVersionEquals(new Number[]{1,1,1,1}, em.getVersion(pc));
+
+ em.getTransaction().begin();
+ pc.setName("updated");
+ em.merge(pc);
+ em.getTransaction().commit();
+ assertVersionEquals(new Number[]{2,2,2,2}, em.getVersion(pc));
+ }
+
+ public void testConcurrentOptimisticUpdateFailsForMultiTable() {
+ OpenJPAEntityManager em1 = emf.createEntityManager();
+ em1.getTransaction().begin();
+ OpenJPAEntityManager em2 = emf.createEntityManager();
+ em2.getTransaction().begin();
+
+ MultiColumnSecondaryVersionPC pc1 = new MultiColumnSecondaryVersionPC();
+ em1.persist(pc1);
+ em1.getTransaction().commit();
+ em1.getTransaction().begin();
+ Object oid = em1.getObjectId(pc1);
+
+
+ MultiColumnSecondaryVersionPC pc2 =
em2.find(MultiColumnSecondaryVersionPC.class, oid);
+ assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2));
+
+ pc1.setName("Updated in em1");
+ pc2.setName("Updated in em2");
+ em1.getTransaction().commit();
+
+ try {
+ em2.getTransaction().commit();
+ fail("Optimistic fail");
+ } catch (Exception e) {
+ } finally {
+ em2.close();
+ }
+ }
+
+ public void testConcurrentOptimisticReadSucceedsForMultiTable() {
+ OpenJPAEntityManager em1 = emf.createEntityManager();
+ em1.getTransaction().begin();
+ OpenJPAEntityManager em2 = emf.createEntityManager();
+ em2.getTransaction().begin();
+
+ MultiColumnSecondaryVersionPC pc1 = new MultiColumnSecondaryVersionPC();
+ em1.persist(pc1);
+ em1.getTransaction().commit();
+ em1.getTransaction().begin();
+ Object oid = em1.getObjectId(pc1);
+
+
+ MultiColumnSecondaryVersionPC pc2 =
em2.find(MultiColumnSecondaryVersionPC.class, oid);
+ assertVersionEquals(em1.getVersion(pc1), em2.getVersion(pc2));
+
+ em1.getTransaction().commit();
+ em2.getTransaction().commit();
+ }
+
static void assertVersionEquals(Object expected, Object actual) {
assertTrue(expected.getClass().isArray());
assertTrue(actual.getClass().isArray());
Modified: openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml?rev=690346&r1=690345&r2=690346&view=diff
==============================================================================
--- openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml
(original)
+++ openjpa/trunk/openjpa-project/src/doc/manual/ref_guide_mapping.xml Fri Aug
29 10:46:15 2008
@@ -1629,6 +1629,11 @@
</listitem>
<listitem>
<para>
+<literal>String table</literal>
+ </para>
+ </listitem>
+ <listitem>
+ <para>
<literal>int length</literal>
</para>
</listitem>
@@ -1674,6 +1679,46 @@
VersionStrategy</classname> annotation described in
<xref linkend="version-strategy"/>.
</para>
+ <para>
+If multiple columns are used for surrogate versioning, then each column,
+by default, uses a version number. But column definition for each version
+column can be set independently to other numeric types. The version values are
+compared to detect optimistic concurrent modification. Such comparison must
+determine whether a version value <literal>v1</literal> represents an earlier,
+later or same with respect to another version value <literal>v2</literal>.
While
+result of such comparison is obvious for a single numeric column that
+monotonically increases on each update, the same is not true when version value
+is an array of numbers. By default, OpenJPA compares a version
+<literal>v1</literal> as later than another version <literal>v2</literal>,
+if any array element of <literal>v1</literal> is
+later than the corresponding element of <literal>v2</literal>.
+<literal>v1</literal> is equal to <literal>v2</literal> if every array element
+is equal and <literal>v1</literal> is earlier to <literal>v1</literal> if some
+elements of <literal>v1</literal> are earlier and rest are equal to
corresponding
+element of <literal>v2</literal>.
+ </para>
+ <para>
+Multiple surrogate version columns can be spread across primary and secondary
+tables. For example, following example shows 3 version columns
+<literal>v01, v11, v12, v21</literal> defined across the primary and secondary
tables of
+a persistent entity
+ </para>
+ <programlisting>
[EMAIL PROTECTED]
[EMAIL PROTECTED](name="PRIMARY")
[EMAIL PROTECTED]({
+ @SecondaryTable(name = "SECONDARY_1"),
+ @SecondaryTable(name = "SECONDARY_2")
+})
[EMAIL PROTECTED]("version-numbers")
[EMAIL PROTECTED]({
+ @VersionColumn(name = "v01") // default is the PRIMARY table
+ @VersionColumn(name = "v11", table="SECONDARY_1",
columnDefinition="FLOAT", scale=3, precision=10),
+ @VersionColumn(name = "v12", table="SECONDARY_1"),
+ @VersionColumn(name = "v21", table="SECONDARY_2"),
+})
+</programlisting>
+
</section>
<section id="ref_guide_mapping_jpa_columns">
<title>