Author: dwoods
Date: Tue Mar 16 21:43:23 2010
New Revision: 924003
URL: http://svn.apache.org/viewvc?rev=924003&view=rev
Log:
OPENJPA-1097 Tests showing how detach()/detachAll()/clear() are currently
working in 1.2.x, where entities serialized after calling detach()/detachAll()
do not contain class wrappers as expected, but entities after calling clear()
still contain class wrappers. Received off-line approval from Mike to only
include the junits in 1.2.x.
Added:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java
(with props)
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
(with props)
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java
(with props)
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java
(with props)
Added:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java
URL:
http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java?rev=924003&view=auto
==============================================================================
---
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java
(added)
+++
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java
Tue Mar 16 21:43:23 2010
@@ -0,0 +1,107 @@
+/*
+ * 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.detach;
+
+import java.io.Serializable;
+import java.sql.Date;
+import java.sql.Time;
+import java.sql.Timestamp;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+...@entity
+...@table(name="Entity20_detach")
+public class Entity20 implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ private Integer id;
+
+ @Column(name = "sqldate" )
+ @Temporal(TemporalType.DATE)
+ private Date sqlDate;
+
+ @Column(name = "sqltime")
+ @Temporal(TemporalType.TIME)
+ private Time sqlTime;
+
+ @Column(name = "sqltimestamp")
+ @Temporal(TemporalType.TIMESTAMP)
+ private Timestamp sqlTimestamp;
+
+ private String name;
+
+ public Entity20() {
+ }
+
+ public Entity20(int id) {
+ this.id = new Integer(id);
+ this.name = this.id.toString();
+ Long time = System.currentTimeMillis();
+ this.sqlTime = new Time(time);
+ this.sqlDate = new Date(time);
+ this.sqlTimestamp = new Timestamp(time);
+ }
+
+ public void setId(Integer id) {
+ this.id = id;
+ }
+
+ public Integer getId() {
+ return id;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setDate(Date d) {
+ sqlDate = d;
+ }
+
+ public Date getDate() {
+ return sqlDate;
+ }
+
+ public void setTime(Time t) {
+ sqlTime = t;
+ }
+
+ public Time getTime() {
+ return sqlTime;
+ }
+
+ public void setTimestamp(Timestamp t) {
+ sqlTimestamp = t;
+ }
+
+ public Timestamp getTimestamp() {
+ return sqlTimestamp;
+ }
+}
Propchange:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/Entity20.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
URL:
http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java?rev=924003&view=auto
==============================================================================
---
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
(added)
+++
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
Tue Mar 16 21:43:23 2010
@@ -0,0 +1,306 @@
+/*
+ * 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.detach;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.ArrayList;
+
+import org.apache.openjpa.conf.Compatibility;
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.persistence.OpenJPAEntityManager;
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+
+public class TestDetachNoProxy extends SingleEMFTestCase {
+
+ private static final int numEntities = 3;
+ private static final String PROXY = new String("$proxy");
+ private Log log;
+
+ public void setUp() {
+ setUp(DROP_TABLES, Entity20.class);
+ log = emf.getConfiguration().getLog("test");
+
+ /* This code is only for 2.0 and later
+ Compatibility compat =
emf.getConfiguration().getCompatibilityInstance();
+ assertNotNull(compat);
+ if (log.isTraceEnabled()) {
+ log.trace("Before set, FlushBeforeDetach=" +
compat.getFlushBeforeDetach());
+ log.trace("Before set, CopyOnDetach=" + compat.getCopyOnDetach());
+ log.trace("Before set, CascadeWithDetach=" +
compat.getCascadeWithDetach());
+ }
+ compat.setFlushBeforeDetach(false);
+ compat.setCopyOnDetach(false);
+ compat.setCascadeWithDetach(false);
+ if (log.isTraceEnabled()) {
+ log.trace("After set, FlushBeforeDetach=" +
compat.getFlushBeforeDetach());
+ log.trace("After set, CopyOnDetach=" + compat.getCopyOnDetach());
+ log.trace("After set, CascadeWithDetach=" +
compat.getCascadeWithDetach());
+ }
+ */
+ createEntities(numEntities);
+ }
+
+ private void createEntities(int count) {
+ Entity20 e20 = null;
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ for (int i=0; i<count; i++) {
+ e20 = new Entity20(i);
+ em.persist(e20);
+ }
+ em.getTransaction().commit();
+ em.close();
+ }
+
+ /*
+ * Verify that returned copy of detached entity does not use the proxy
classes.
+ */
+ public void testDetach() {
+ if (log.isTraceEnabled())
+ log.trace("***** testDetach() *****");
+ Integer id = new Integer(0);
+ OpenJPAEntityManager em = emf.createEntityManager();
+
+ em.clear();
+ Entity20 e20 = em.find(Entity20.class, id);
+ if (log.isTraceEnabled())
+ log.trace("** after find");
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+
+ // pre openjpa-2.0.0 behavior, where detach() returned the updated
entity
+ Entity20 e20Copy = em.detach(e20);
+ if (log.isTraceEnabled())
+ log.trace("** after detach");
+ // original entity should have proxy classes and should not be detached
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+ // returned entity should not have any proxy classes and should be
detached
+ assertFalse(em.contains(e20Copy));
+ assertTrue(em.isDetached(e20Copy));
+ verifySerializable(e20Copy, false, false);
+
+ em.close();
+ }
+
+ /*
+ * This only works on 2.0.0 and later - new method
+ * Verify that a detachCopy() returned entity does not contain any proxy
classes.
+ *
+ public void testDetachCopy() {
+ if (log.isTraceEnabled())
+ log.trace("***** testDetachCopy() *****");
+ Integer id = new Integer(0);
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.clear();
+
+ Entity20 e20 = em.find(Entity20.class, id);
+ if (log.isTraceEnabled())
+ log.trace("** after find");
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+
+ // This only works on 2.0 and later - new method
+ Entity20 e20copy = em.detachCopy(e20);
+ if (log.isTraceEnabled())
+ log.trace("** after detachCopy");
+ // verify e20 is same as above
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true);
+ // verify copy does not have any proxy classes (in-place updated) is
detached
+ assertFalse(em.contains(e20copy));
+ assertTrue(em.isDetached(e20copy));
+ verifySerializable(e20copy, false, false);
+
+ em.close();
+ }
+ */
+
+ /*
+ * Verify that returned copies of detachAll() entities do not use the
proxy classes.
+ */
+ public void testDetachAll() {
+ if (log.isTraceEnabled())
+ log.trace("***** testDetachAll() *****");
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.clear();
+
+ ArrayList<Entity20> e20List = new ArrayList<Entity20>(numEntities);
+ for (int i=0; i<numEntities; i++) {
+ Entity20 e20 = em.find(Entity20.class, new Integer(i));
+ e20List.add(e20);
+ if (log.isTraceEnabled())
+ log.trace("** after find Entity20(" + i + ")");
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+ }
+
+ // pre openjpa-2.0.0 behavior, where detachAll() returned the updated
entities
+ ArrayList<Entity20> e20ListCopy = new
ArrayList<Entity20>(em.detachAll(e20List));
+ for (int i=0; i<numEntities; i++) {
+ if (log.isTraceEnabled())
+ log.trace("** after EM.detachAll() verify e20List(" + i + ")");
+ Entity20 e20 = e20List.get(i);
+ // original entity should have proxy classes and should not be
detached
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+ }
+ for (int i=0; i<numEntities; i++) {
+ if (log.isTraceEnabled())
+ log.trace("** after EM.detachAll() verify e20ListCopy(" + i +
")");
+ Entity20 e20 = e20ListCopy.get(i);
+ // entity should not have any proxy classes and should be detached
+ assertFalse(em.contains(e20));
+ assertTrue(em.isDetached(e20));
+ verifySerializable(e20, false, false);
+ }
+
+ em.close();
+ }
+
+ /*
+ * Verify that after EM.clear() entities still contain proxy classes.
+ */
+ public void testClear() {
+ if (log.isTraceEnabled())
+ log.trace("***** testClear() *****");
+ OpenJPAEntityManager em = emf.createEntityManager();
+ em.clear();
+
+ ArrayList<Entity20> e20List = new ArrayList<Entity20>(numEntities);
+ for (int i=0; i<numEntities; i++) {
+ Entity20 e20 = em.find(Entity20.class, new Integer(i));
+ e20List.add(e20);
+ if (log.isTraceEnabled())
+ log.trace("** after find Entity20(" + i + ")");
+ assertTrue(em.contains(e20));
+ assertFalse(em.isDetached(e20));
+ verifySerializable(e20, true, false);
+ }
+
+ em.clear();
+
+ for (int i=0; i<numEntities; i++) {
+ if (log.isTraceEnabled())
+ log.trace("** after EM.clear() verify Entity20(" + i + ")");
+ Entity20 e20 = e20List.get(i);
+ assertFalse(em.contains(e20));
+ assertTrue(em.isDetached(e20));
+ // entity should still have proxy classes and is detached,
+ // Current Behavior -
+ // the $proxy classes are not removed during serialization
+ verifySerializable(e20, true, true);
+ // Proposed OPENJPA-1097 new behavior - $proxy classes are removed
+ // verifySerializable(e20, true, false);
+ }
+
+ em.close();
+ }
+
+ /**
+ * Test that the entity is/is not using our $proxy classes before
+ * and after serialization.
+ *
+ * @param e20 Entity to test.
+ * @param usesProxyBefore verify that the entity uses the $proxy classes
+ * before serialization if true and does not if false.
+ * @param usesProxyAfter verify that the entity uses the $proxy classes
+ * after serialization if true and does not if false.
+ */
+ private void verifySerializable(Entity20 e20, boolean usesProxyBefore,
+ boolean usesProxyAfter) {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = null;
+ byte[] e20bytes = null;
+
+ if (log.isTraceEnabled())
+ log.trace("verifySerializable() - before serialize");
+ verifyEntities(e20, usesProxyBefore);
+
+ // first serialize
+ try {
+ oos = new ObjectOutputStream(baos);
+ oos.writeObject(e20);
+ e20bytes = baos.toByteArray();
+ } catch (IOException e) {
+ fail(e.toString());
+ } finally {
+ try {
+ if (oos != null)
+ oos.close();
+ } catch (IOException e) {
+ }
+ }
+
+ // then deserialize and assert no $proxy classes exist
+ ByteArrayInputStream bais = new ByteArrayInputStream(e20bytes);
+ ObjectInputStream ois = null;
+ Entity20 e20new = null;
+ try {
+ ois = new ObjectInputStream(bais);
+ e20new = (Entity20) ois.readObject();
+ if (log.isTraceEnabled())
+ log.trace("verifySerializable() - after deserialize");
+ verifyEntities(e20new, usesProxyAfter);
+ } catch (IOException e) {
+ fail(e.toString());
+ } catch (ClassNotFoundException e) {
+ fail(e.toString());
+ } finally {
+ try {
+ if (ois != null)
+ ois.close();
+ } catch (IOException e) {
+ }
+ }
+
+ }
+
+ private void verifyEntities(Entity20 e20, boolean usesProxy) {
+ if (log.isTraceEnabled()) {
+ log.trace("asserting expected proxy usage");
+ printClassNames(e20);
+ }
+ assertTrue("Expected sqlDate endsWith($proxy) to return " + usesProxy,
+ usesProxy ==
e20.getDate().getClass().getCanonicalName().endsWith(PROXY));
+ assertTrue("Expected sqlTime endsWith($proxy) to return " + usesProxy,
+ usesProxy ==
e20.getTime().getClass().getCanonicalName().endsWith(PROXY));
+ assertTrue("Expected sqlTimestamp endsWith($proxy) to return " +
usesProxy,
+ usesProxy ==
e20.getTimestamp().getClass().getCanonicalName().endsWith(PROXY));
+
+ }
+
+ private void printClassNames(Entity20 e20) {
+ if (log.isTraceEnabled()) {
+ log.trace("sqlDate = " +
e20.getDate().getClass().getCanonicalName());
+ log.trace("sqlTime = " +
e20.getTime().getClass().getCanonicalName());
+ log.trace("sqlTimestamp = " +
e20.getTimestamp().getClass().getCanonicalName());
+ }
+ }
+
+}
Propchange:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/detach/TestDetachNoProxy.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java
URL:
http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java?rev=924003&view=auto
==============================================================================
---
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java
(added)
+++
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java
Tue Mar 16 21:43:23 2010
@@ -0,0 +1,191 @@
+/*
+ * 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.proxy;
+
+import javax.persistence.EntityManager;
+
+import org.apache.openjpa.persistence.test.SingleEMFTestCase;
+import org.apache.openjpa.util.ChangeTracker;
+import org.apache.openjpa.util.ProxyCollection;
+
+/**
+ * Tests proxying and change tracking of collection fields for modification in
+ * detached state.
+ *
+ * Originally reported in
+ * <A HREF="https://issues.apache.org/jira/browse/OPENJPA-628">OPENJPA-628</A>
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public class TestProxyCollection extends SingleEMFTestCase {
+ public void setUp() {
+ super.setUp(CLEAR_TABLES, TreeNode.class);
+ }
+ /**
+ * Tests that a uniform tree is created with expected fan outs at each
+ * level. This is not a persistent operation, just in-memory.
+ */
+ public void testCreateTree() {
+ TreeNode root = new TreeNode();
+ root.setName("0");
+ int[] fanOuts = {1,2,3};
+ root.createTree(fanOuts);
+ assertArrayEquals(fanOuts, root.getFanOuts());
+ }
+
+ /**
+ * Tests that a uniform tree can be modified with different fan outs at
each
+ * level. This is not a persistent operation, just in-memory.
+ */
+ public void testModifyTree() {
+ int[] fanOuts = {1,2,2,4};
+ int[] newFanOuts = {1,3,1,2};
+ TreeNode root = new TreeNode();
+ root.createTree(fanOuts);
+ assertArrayEquals(fanOuts, root.getFanOuts());
+
+ root.modify(newFanOuts);
+ assertArrayEquals(newFanOuts, root.getFanOuts());
+ }
+
+ /**
+ * Tests that a uniform tree is persisted and later fetched back with
same
+ * number of children at every level.
+ */
+ public void testPersistTree() {
+ int[] fanOuts = {2,3,4};
+ verify(create(fanOuts), fanOuts);
+ }
+
+ public void testAddNodeAtLeaf() {
+ int[] original = {1,2,3};
+ int[] modifier = {1,2,4}; // add new child at Level 2
+ createModifyAndMerge(original, modifier);
+ }
+
+ public void testAddNewLevel() {
+ int[] original = {1,2,3};
+ int[] modifier = {1,2,3,2}; // add 2 new children at new Level
+ createModifyAndMerge(original, modifier);
+ }
+
+ public void testAddAndRemove() {
+ int[] original = {2,3,4};
+ int[] modifier = {4,3,2}; // add 1 at Level 1 + remove 1 at
Level 3
+ createModifyAndMerge(original, modifier);
+ }
+
+ public void testAddAtAllLevel() {
+ int[] original = {2,3,4};
+ int[] modifier = {3,4,5}; // add 1 at each Level
+ createModifyAndMerge(original, modifier);
+ }
+
+ public void testRemoveAtAllLevel() {
+ int[] original = {2,3,4};
+ int[] modifier = {1,2,3}; // remove 1 from each Level
+ createModifyAndMerge(original, modifier);
+ }
+ /**
+ * Create a uniform tree with original fanout.
+ * Persist.
+ * Verify in a separate persistence context that the tree is stored.
+ * Modify the tree by adding or deleting nodes according to the given
+ * modified fanouts outside a transaction.
+ * Merge the changes.
+ * Verify that the changes are merged by fetching the modified version.
+ *
+ * @param original
+ * @param modified
+ */
+ void createModifyAndMerge(int[] original, int[] modifier) {
+ TreeNode root = create(original);
+
+ EntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ TreeNode modified = em.find(TreeNode.class, root.getId());
+ modified.modify(modifier);
+ em.merge(modified);
+ em.getTransaction().commit();
+
+ em.clear();
+
+ assertProxyCollection(root.getNodes(), false);
+
+ verify(root, modifier);
+ }
+
+ /**
+ * Create a uniform tree with given fan out.
+ * Persist.
+ * Verify that the tree is stored by fetching it in a separate
persistence
+ * context.
+ */
+ TreeNode create(int[] original) {
+ TreeNode root = new TreeNode();
+ root.createTree(original);
+
+ EntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ em.persist(root);
+ em.getTransaction().commit();
+ em.clear();
+
+ return root;
+ }
+
+ void verify(TreeNode node, int[] fanOuts) {
+ EntityManager em = emf.createEntityManager();
+ em.getTransaction().begin();
+ TreeNode test = em.find(TreeNode.class, node.getId());
+ assertNotNull(test);
+ assertArrayEquals(fanOuts, test.getFanOuts());
+ }
+
+ /** Asserts the given arrays have exactly same elements at the same
index.
+ */
+ void assertArrayEquals(int[] a, int[] b) {
+ assertEquals(a.length, b.length);
+ for (int i = 0; i<a.length; i++)
+ assertEquals(a[i], b[i]);
+ }
+
+ /**
+ * Asserts that the given object is a proxy collection and whether it
is
+ * tracking changes.
+ */
+ void assertProxyCollection(Object o, boolean tracking) {
+ assertTrue(o instanceof ProxyCollection);
+ ChangeTracker tracker = ((ProxyCollection)o).getChangeTracker();
+ if (tracking) {
+ assertNotNull(tracker);
+ assertTrue(tracker.isTracking());
+ } else {
+ assertFalse(tracker.isTracking());
+ }
+ }
+
+ /**
+ * Asserts that the given object is NOT a proxy collection.
+ */
+ void assertNotProxyCollection(Object o) {
+ assertFalse(o instanceof ProxyCollection);
+ }
+}
Propchange:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TestProxyCollection.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java
URL:
http://svn.apache.org/viewvc/openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java?rev=924003&view=auto
==============================================================================
---
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java
(added)
+++
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java
Tue Mar 16 21:43:23 2010
@@ -0,0 +1,231 @@
+/*
+ * 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.proxy;
+
+import java.io.PrintStream;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.Version;
+
+import org.apache.openjpa.persistence.DetachedState;
+import org.apache.openjpa.persistence.ElementDependent;
+import org.apache.openjpa.persistence.jdbc.ElementJoinColumn;
+import org.apache.openjpa.persistence.jdbc.OrderColumn;
+
+/**
+ * Persistent entity for testing adding/removing elements of collection valued
+ * field while in detached state.
+ *
+ * Node refers to a list of Nodes as children.
+ *
+ * Contains recursive methods to create or modify uniform subtree. Uniform
+ * subtree implies that each child at a level L has equal number of
+ * grand children at level L+1.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+...@entity
+...@detachedstate
+public class TreeNode implements Serializable {
+ @Id
+ @GeneratedValue
+ private long id;
+
+ private String name;
+
+ @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
+ @ElementJoinColumn(name = "ParentID")
+ @OrderColumn(name = "Sequence")
+ @ElementDependent
+ private List<TreeNode> childern = new ArrayList<TreeNode>();
+
+ @Version
+ private int version;
+
+ public long getId() {
+ return id;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Add a child node at the end of the current list of children.
+ */
+ public void addNode(TreeNode node) {
+ addNode(node, childern.size());
+ }
+
+ /**
+ * Insert a child node at the specified position in the list of
children.
+ */
+ public void addNode(TreeNode node, int position) {
+ checkSequenceRange(position);
+ childern.add(position, node);
+ }
+
+ public boolean removeNode(TreeNode node) {
+ return childern.remove(node);
+ }
+
+ public TreeNode removeNode(int sequence) {
+ checkSequenceRange(sequence);
+ return childern.remove(sequence);
+ }
+
+ public TreeNode getNode(int sequence) {
+ checkSequenceRange(sequence);
+ return childern.get(sequence);
+ }
+
+ public List<TreeNode> getNodes() {
+ return childern;
+ }
+
+ public void clearNodes() {
+ childern.clear();
+ }
+
+ public boolean isLeaf() {
+ return childern.isEmpty();
+ }
+
+ protected void checkSequenceRange(int sequence)
+ throws IllegalArgumentException {
+ int size = childern.size();
+ if (sequence < 0 || sequence > size)
+ throw new IllegalArgumentException("Sequence number is
beyond "
+ + "range of 0 to " + size + ".");
+ }
+
+ public int getVersion() {
+ return version;
+ }
+
+ /**
+ * Create a uniform subtree below the receiver. Uniform subtree implies
that
+ * each child at a level L has equal number of grand children at level
L+1.
+ *
+ * @param fanOuts
+ * array of fan outs for children at every level.
+ */
+ public void createTree(int[] fanOuts) {
+ if (fanOuts.length == 0)
+ return;
+ int[] nextFanOuts = new int[fanOuts.length];
+ System.arraycopy(fanOuts, 1, nextFanOuts, 0, fanOuts.length -
1);
+ for (int j = 0; j < fanOuts[0]; j++) {
+ TreeNode child = new TreeNode();
+ child.setName(getName() + "." + j);
+ addNode(child);
+ child.createTree(nextFanOuts);
+ }
+ }
+
+ /**
+ * Add or remove subtree of the receiver to match the given fanOut.
+ */
+ public void modify(int[] fanOuts) {
+ if (fanOuts == null || fanOuts.length == 0)
+ return;
+ int n = fanOuts[0];
+ int[] nextFanOuts = new int[fanOuts.length];
+ System.arraycopy(fanOuts, 1, nextFanOuts, 0, fanOuts.length -
1);
+ List<TreeNode> children = getNodes();
+ int diff = children.size() - n;
+ if (diff < 0) {
+ for (int i = 0; i < -diff; i++) {
+ TreeNode newChild = new TreeNode();
+ int position = getNodes().size();
+ newChild.setName(getName() + "." + position);
+ addNode(newChild);
+ }
+ } else if (diff > 0) {
+ for (int i = 0; i < diff; i++) {
+ int position = getNodes().size() - 1;
+ removeNode(position);
+ }
+ }
+ children = getNodes();
+ for (TreeNode child : children) {
+ child.modify(nextFanOuts);
+ }
+ }
+
+ /**
+ * Get the fan outs of the given receiver. Assumes that the subtree is
+ * uniform. Otherwise throws exception.
+ */
+ public int[] getFanOuts() {
+ return getFanOuts(new int[] {});
+ }
+
+ private int[] getFanOuts(int[] list) {
+ List<TreeNode> children = getNodes();
+ if (children.isEmpty())
+ return list;
+ int[] fanOuts = new int[children.size()];
+ int i = 0;
+ for (TreeNode child : children) {
+ fanOuts[i++] = child.getNodes().size();
+ }
+ for (int j = 0; j < fanOuts.length - 1; j++)
+ if (fanOuts[j] != fanOuts[j + 1])
+ throw new RuntimeException("non-uniform fanouts
for children "
+ + " of " + getName());
+
+ int[] newList = new int[list.length + 1];
+ System.arraycopy(list, 0, newList, 0, list.length);
+ newList[list.length] = children.size();
+ return children.get(0).getFanOuts(newList);
+ }
+
+ /**
+ * Prints this receiver and its subtree.
+ */
+ public void print(PrintStream out) {
+ print(2, out);
+ }
+
+ private void print(int tab, PrintStream out) {
+ for (int i = 0; i < tab; i++)
+ out.print(" ");
+ out.println(getName());
+ for (TreeNode child : getNodes()) {
+ child.print(tab + 2, out);
+ }
+ }
+
+}
Propchange:
openjpa/branches/1.2.x/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/proxy/TreeNode.java
------------------------------------------------------------------------------
svn:eol-style = native