diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyConcurrentMaps.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyConcurrentMaps.java new file mode 100644 index 000000000..76f500f65 --- /dev/null +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyConcurrentMaps.java @@ -0,0 +1,54 @@ +/* + * 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.util; + +import java.util.Map; + +/** + * Utility methods used by concurrent map proxies. + * + */ +public class ProxyConcurrentMaps extends ProxyMaps { + /** + * Call before invoking {@link Map#remove} on super. + */ + public static boolean beforeRemove(ProxyMap map, Object key, Object value) { + dirty(map, false); + return map.containsKey(key); + } + + /** + * Call after invoking {@link Map#remove} on super. + * + * @param ret the return value from the super's method + * @param before the return value from {@link #beforeRemove} + * @return the value to return from {@link Map#remove} + */ + public static boolean afterRemove(ProxyMap map, Object key, Object value, boolean ret, + boolean before) { + if (before) { + if (map.getChangeTracker() != null) { + ((MapChangeTracker) map.getChangeTracker()).removed(key, ret); + } + removed(map, key, true); + removed(map, ret, false); + } + return ret; + } +} diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java index 4ce438aee..af441740c 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java @@ -59,6 +59,8 @@ import org.apache.openjpa.lib.util.Options; import org.apache.openjpa.lib.util.concurrent.NullSafeConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import serp.bytecode.BCClass; import serp.bytecode.BCField; import serp.bytecode.BCMethod; @@ -560,7 +562,9 @@ public class ProxyManagerImpl delegateConstructors(bc, type); addProxyMethods(bc, false); addProxyMapMethods(bc, type); - proxyRecognizedMethods(bc, type, ProxyMaps.class, ProxyMap.class); + Class mapProxyClassType = + ConcurrentMap.class.isAssignableFrom(type) ? ProxyConcurrentMaps.class : ProxyMaps.class; + proxyRecognizedMethods(bc, type, mapProxyClassType, ProxyMap.class); proxySetters(bc, type); addWriteReplaceMethod(bc, runtime); return bc; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityLeft.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityLeft.java new file mode 100644 index 000000000..879e4d02e --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityLeft.java @@ -0,0 +1,64 @@ +/* + * 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.relations; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +@Entity +public class ConcurrentEntityLeft { + @Id + private int id; + + private String strData; + + @ManyToOne + @JoinColumn(name="right_id", referencedColumnName="id") + private ConcurrentEntityRight rightEntity; + + public ConcurrentEntityLeft() { + + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getStrData() { + return strData; + } + + public void setStrData(String strData) { + this.strData = strData; + } + + public ConcurrentEntityRight getRightEntity() { + return rightEntity; + } + + public void setRightEntity(ConcurrentEntityRight rightEntity) { + this.rightEntity = rightEntity; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityRight.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityRight.java new file mode 100644 index 000000000..09bceae81 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/ConcurrentEntityRight.java @@ -0,0 +1,64 @@ +/* + * 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.relations; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.MapKey; +import javax.persistence.OneToMany; + +@Entity +public class ConcurrentEntityRight { + @Id + private int id; + + private String strData; + + @OneToMany(mappedBy="rightEntity", targetEntity=ConcurrentEntityLeft.class, + cascade={javax.persistence.CascadeType.ALL}) + @MapKey(name="strData") + private Map leftEntityMap; + + public ConcurrentEntityRight() { + leftEntityMap = new ConcurrentHashMap(); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getStrData() { + return strData; + } + + public void setStrData(String strData) { + this.strData = strData; + } + + public Map getLeftEntityMap() { + return leftEntityMap; + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestConcurrentMap.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestConcurrentMap.java new file mode 100644 index 000000000..1435d27ea --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/relations/TestConcurrentMap.java @@ -0,0 +1,48 @@ +/* + * 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.relations; + +import org.apache.openjpa.persistence.test.SingleEMTestCase; + +public class TestConcurrentMap extends SingleEMTestCase { + public void setUp() { + setUp(ConcurrentEntityLeft.class, ConcurrentEntityRight.class, + CLEAR_TABLES); + } + + public void testConcurrentMap001() { + em.getTransaction().begin(); + + ConcurrentEntityLeft left = new ConcurrentEntityLeft(); + left.setId(1); + left.setStrData("Lefty"); + + ConcurrentEntityRight right = new ConcurrentEntityRight(); + right.setId(1); + right.setStrData("Poncho"); + + em.persist(left); + em.persist(right); + + left.setRightEntity(right); + right.getLeftEntityMap().put(left.getStrData(), left); + + em.getTransaction().commit(); + } +}