openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ppod...@apache.org
Subject svn commit: r690346 - in /openjpa/trunk: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/strats/ openjpa-jdbc/src/main/resources/org/apache/openjpa/jdbc/meta/ openjpa-persistence-jdbc/src...
Date Fri, 29 Aug 2008 17:46:16 GMT
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
+ * 
+ */
+@Entity
+@Table(name="MCSV")
+@SecondaryTables({ 
+	@SecondaryTable(name = "MCSV1", pkJoinColumns=@PrimaryKeyJoinColumn(name="ID")),
+	@SecondaryTable(name = "MCSV2", pkJoinColumns=@PrimaryKeyJoinColumn(name="ID")) 
+})
+@VersionStrategy("version-numbers")
+@VersionColumns({ 
+	@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
+@Table(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>
+@Entity
+@Table(name="PRIMARY")
+@SecondaryTables({ 
+    @SecondaryTable(name = "SECONDARY_1"),
+    @SecondaryTable(name = "SECONDARY_2") 
+})
+@VersionStrategy("version-numbers")
+@VersionColumns({ 
+    @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>



Mime
View raw message