You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2007/11/16 02:09:28 UTC
svn commit: r595510 - in /openjpa/trunk:
openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/
openjpa-kernel/src/main/java/org/apache/openjpa/enhance/
openjpa-kernel/src/main/java/org/apache/openjpa/kernel/
openjpa-persistence-jdbc/ openjpa-persi...
Author: pcl
Date: Thu Nov 15 17:09:26 2007
New Revision: 595510
URL: http://svn.apache.org/viewvc?rev=595510&view=rev
Log:
OPENJPA-316
Added:
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestUnenhancedOneToMany.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedMany.java
openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedOne.java
Removed:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicPCHelper.java
Modified:
openjpa/trunk/openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/RedefinitionHelper.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
openjpa/trunk/openjpa-persistence-jdbc/pom.xml
Modified: openjpa/trunk/openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java?rev=595510&r1=595509&r2=595510&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java (original)
+++ openjpa/trunk/openjpa-kernel-5/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java Thu Nov 15 17:09:26 2007
@@ -18,6 +18,7 @@
*/
package org.apache.openjpa.enhance;
+import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -34,6 +35,7 @@
import org.apache.openjpa.lib.util.BytecodeWriter;
import org.apache.openjpa.lib.util.JavaVersions;
import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.lib.util.Files;
import org.apache.openjpa.lib.util.Localizer.Message;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
@@ -249,15 +251,35 @@
// but do set the metadata accordingly.
if (enhancer.isAlreadyRedefined())
ints.add(bc.getType());
- else if (JavaVersions.VERSION >= 5)
+ else if (JavaVersions.VERSION >= 5) {
map.put(bc.getType(), bc.toByteArray());
+ debugBytecodes(bc);
+ }
} else {
if (!enhancer.isAlreadySubclassed()) {
+ debugBytecodes(bc);
+
// this is the new subclass
ClassLoader loader = GeneratedClasses.getMostDerivedLoader(
cls, PersistenceCapable.class);
subs.add(GeneratedClasses.loadBCClass(bc, loader));
}
+ }
+ }
+
+ private static void debugBytecodes(BCClass bc) throws IOException {
+ // Write the bytecodes to disk for debugging purposes.
+ if ("true".equals(System.getProperty(
+ ManagedClassSubclasser.class.getName() + ".dumpBytecodes")))
+ {
+ File tmp = new File(System.getProperty("java.io.tmpdir"));
+ File dir = new File(tmp, "openjpa");
+ dir = new File(dir, "pcsubclasses");
+ dir.mkdirs();
+ dir = Files.getPackageFile(dir, bc.getPackageName(), true);
+ File f = new File(dir, bc.getClassName() + ".class");
+ System.err.println("Writing to " + f);
+ bc.write(f);
}
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/RedefinitionHelper.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/RedefinitionHelper.java?rev=595510&r1=595509&r2=595510&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/RedefinitionHelper.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/RedefinitionHelper.java Thu Nov 15 17:09:26 2007
@@ -18,8 +18,15 @@
*/
package org.apache.openjpa.enhance;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.lang.reflect.Method;
+import java.lang.reflect.Field;
+
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StateManagerImpl;
+import org.apache.openjpa.meta.FieldMetaData;
+import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.ImplHelper;
/**
@@ -184,5 +191,47 @@
if (sm != null)
sm.settingObjectField(pc, idx, cur, next,
OpenJPAStateManager.SET_USER);
+ }
+
+ /**
+ * Create a container instance that will delegate back to the state
+ * manager to emulate lazy loading. This is used by PC subclasses for
+ * unenhanced types that could not be redefined, and thus do not have
+ * field-interception capabilities. Do this for all collection and
+ * map field types, even if they are in the dfg, in case the fetch
+ * groups are reset at runtime.
+ *
+ * @since 1.1.0
+ */
+ public static void assignLazyLoadProxies(StateManagerImpl sm) {
+ FieldMetaData[] fmds = sm.getMetaData().getFields();
+ for (int i = 0; i < fmds.length; i++) {
+ switch (fmds[i].getTypeCode()) {
+ case JavaTypes.COLLECTION:
+ case JavaTypes.MAP:
+ PersistenceCapable pc = sm.getPersistenceCapable();
+ Field field = (Field) fmds[i].getBackingMember();
+ Reflection.set(pc, field,
+ newLazyLoadingProxy(fmds[i].getDeclaredType(), i, sm));
+ break;
+ }
+ }
+ }
+
+ private static Object newLazyLoadingProxy(Class type, final int idx,
+ final StateManagerImpl sm) {
+ InvocationHandler handler = new InvocationHandler() {
+
+ public Object invoke(Object proxy, Method method, Object[] args)
+ throws Throwable {
+ // this will replace the field in the instance, so the dynamic
+ // proxy should only be called the first time a
+ // lazy-load-proxied field is used in normal usage.
+ Object delegate = sm.fetch(idx);
+ return method.invoke(delegate, args);
+ }
+ };
+ return Proxy.newProxyInstance(type.getClassLoader(),
+ new Class[] { type }, handler);
}
}
Modified: openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java?rev=595510&r1=595509&r2=595510&view=diff
==============================================================================
--- openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java (original)
+++ openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/StateManagerImpl.java Thu Nov 15 17:09:26 2007
@@ -21,16 +21,25 @@
import java.io.IOException;
import java.io.ObjectOutput;
import java.lang.reflect.Modifier;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.TimeZone;
import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration;
+import org.apache.openjpa.enhance.DynamicPersistenceCapable;
import org.apache.openjpa.enhance.FieldManager;
+import org.apache.openjpa.enhance.ManagedInstanceProvider;
import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.enhance.PersistenceCapable;
+import org.apache.openjpa.enhance.RedefinitionHelper;
import org.apache.openjpa.enhance.StateManager;
-import org.apache.openjpa.enhance.ManagedInstanceProvider;
-import org.apache.openjpa.enhance.DynamicPersistenceCapable;
import org.apache.openjpa.event.LifecycleEvent;
import org.apache.openjpa.event.LifecycleEventManager;
import org.apache.openjpa.lib.util.Localizer;
@@ -43,6 +52,7 @@
import org.apache.openjpa.meta.ValueStrategies;
import org.apache.openjpa.util.ApplicationIds;
import org.apache.openjpa.util.Exceptions;
+import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.InvalidStateException;
import org.apache.openjpa.util.ObjectNotFoundException;
@@ -50,7 +60,6 @@
import org.apache.openjpa.util.ProxyManager;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
import org.apache.openjpa.util.UserException;
-import org.apache.openjpa.util.ImplHelper;
import serp.util.Numbers;
/**
@@ -306,8 +315,11 @@
// if this is a non-tracking PC, add a hard ref to the appropriate data
// sets and give it an opportunity to make a state snapshot.
- if (!isIntercepting())
+ if (!isIntercepting()) {
saveFields(true);
+ if (!isNew())
+ RedefinitionHelper.assignLazyLoadProxies(this);
+ }
}
/**
@@ -315,6 +327,8 @@
* from {@link ClassMetaData#isIntercepting()} in that it checks for
* property access + subclassing in addition to the redefinition /
* enhancement checks.
+ *
+ * @since 1.0.0
*/
public boolean isIntercepting() {
if (getMetaData().isIntercepting())
Modified: openjpa/trunk/openjpa-persistence-jdbc/pom.xml
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/pom.xml?rev=595510&r1=595509&r2=595510&view=diff
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/pom.xml (original)
+++ openjpa/trunk/openjpa-persistence-jdbc/pom.xml Thu Nov 15 17:09:26 2007
@@ -398,6 +398,7 @@
<fileset id="enhance.path.ref"
dir="${project.build.testOutputDirectory}">
<include name="**/*.class"/>
+ <exclude name="**/Test*.class"/>
<exclude name="**/inheritance/serializable/*.class"/>
<exclude name="**/xml/*.class"/>
<exclude name="**/Unenhanced*.class"/>
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestUnenhancedOneToMany.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestUnenhancedOneToMany.java?rev=595510&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestUnenhancedOneToMany.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestUnenhancedOneToMany.java Thu Nov 15 17:09:26 2007
@@ -0,0 +1,118 @@
+/*
+ * 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.enhance;
+
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+
+import org.apache.openjpa.persistence.test.SingleEMTestCase;
+
+public class TestUnenhancedOneToMany extends SingleEMTestCase {
+
+ public void setUp() {
+ setUp(UnenhancedOne.class, UnenhancedMany.class, CLEAR_TABLES);
+ }
+
+ public void testOneToMany() throws Exception {
+ assertFalse(PersistenceCapable.class.isAssignableFrom(
+ UnenhancedOne.class));
+ assertFalse(PersistenceCapable.class.isAssignableFrom(
+ UnenhancedMany.class));
+
+ em.getTransaction().begin();
+
+ UnenhancedOne one = new UnenhancedOne(1000);
+
+ UnenhancedMany manyA = new UnenhancedMany(1);
+ one.getMany().add(manyA);
+ manyA.setOne(one);
+
+ UnenhancedMany manyB = new UnenhancedMany(2);
+ one.getMany().add(manyB);
+ manyB.setOne(one);
+
+ UnenhancedMany manyC = new UnenhancedMany(3);
+ one.getMany().add(manyC);
+ manyC.setOne(one);
+
+ // em should not know about our entities
+ assertFalse(em.contains(one));
+ assertFalse(em.contains(manyA));
+ assertFalse(em.contains(manyB));
+ assertFalse(em.contains(manyC));
+
+ // persist the entity
+ em.persist(one);
+ em.persist(manyA);
+ em.persist(manyB);
+ em.persist(manyC);
+ em.flush();
+
+ // em should now be aware of our entity
+ assertTrue(em.contains(one));
+ assertTrue(em.contains(manyA));
+ assertTrue(em.contains(manyB));
+ assertTrue(em.contains(manyC));
+
+ em.getTransaction().commit();
+
+ // recreate entity manager to avoid caching
+ one = null;
+ manyA = null;
+ manyB = null;
+ manyC = null;
+ em.close();
+ em = emf.createEntityManager();
+ em.getTransaction().begin();
+
+ // reload one
+ one = em.find(UnenhancedOne.class, 1000);
+ assertNotNull("one is null", one);
+
+ // verify one.getMany(); ensure that it's a dynamic proxy before
+ // it is accessed
+ assertTrue(Proxy.isProxyClass(one.many.getClass()));
+ assertNotNull("one.getMany() is null", one.getMany());
+ Collection<UnenhancedMany> many = one.getMany();
+ assertEquals(3, many.size());
+
+ // reload the many
+ manyA = em.find(UnenhancedMany.class, 1);
+ assertNotNull("manyA is null", manyA);
+ manyB = em.find(UnenhancedMany.class, 2);
+ assertNotNull("manyB is null", manyA);
+ manyC = em.find(UnenhancedMany.class, 3);
+ assertNotNull("manyc is null", manyA);
+
+ // verify many.getOne()
+ assertNotNull("manyA.getOne() is null", manyA.getOne());
+ assertEquals(one, manyA.getOne());
+ assertNotNull("manyB.getOne() is null", manyB.getOne());
+ assertEquals(one, manyB.getOne());
+ assertNotNull("manyC.getOne() is null", manyC.getOne());
+ assertEquals(one, manyC.getOne());
+
+ // verify collection contains each many
+ assertTrue(many.contains(manyA));
+ assertTrue(many.contains(manyB));
+ assertTrue(many.contains(manyC));
+
+ em.getTransaction().commit();
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedMany.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedMany.java?rev=595510&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedMany.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedMany.java Thu Nov 15 17:09:26 2007
@@ -0,0 +1,69 @@
+/**
+ *
+ * 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.enhance;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import java.io.Serializable;
+
+@Entity
+public class UnenhancedMany implements Serializable, Cloneable {
+ private static final long serialVersionUID = 4041356744771116705L;
+
+ @Id
+ private int id;
+
+ @ManyToOne
+ private UnenhancedOne one;
+
+ public UnenhancedMany() {
+ }
+
+ public UnenhancedMany(int id) {
+ this.id = id;
+ }
+
+ public long getId() {
+ return id;
+ }
+
+ public UnenhancedOne getOne() {
+ return one;
+ }
+
+ public void setOne(UnenhancedOne one) {
+ this.one = one;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null) return false;
+ if (!getClass().isAssignableFrom(o.getClass())) return false;
+
+ return id == ((UnenhancedMany) o).id;
+ }
+
+ public int hashCode() {
+ return id;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}
Added: openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedOne.java
URL: http://svn.apache.org/viewvc/openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedOne.java?rev=595510&view=auto
==============================================================================
--- openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedOne.java (added)
+++ openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedOne.java Thu Nov 15 17:09:26 2007
@@ -0,0 +1,67 @@
+/**
+ *
+ * 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.enhance;
+
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashSet;
+
+@Entity
+public class UnenhancedOne implements Serializable, Cloneable {
+ private static final long serialVersionUID = -5834998517804641711L;
+
+ @Id
+ private int id;
+
+ @OneToMany
+ Collection<UnenhancedMany> many = new HashSet<UnenhancedMany>();
+
+ public UnenhancedOne() {
+ }
+
+ public UnenhancedOne(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public Collection<UnenhancedMany> getMany() {
+ return many;
+ }
+
+ public boolean equals(Object o) {
+ if (o == this) return true;
+ if (o == null) return false;
+ if (!getClass().isAssignableFrom(o.getClass())) return false;
+
+ return id == ((UnenhancedOne) o).id;
+ }
+
+ public int hashCode() {
+ return id;
+ }
+
+ public Object clone() throws CloneNotSupportedException {
+ return super.clone();
+ }
+}