OPENJPA-1175 Updated util methods to handle load state checking of embeddables and collections.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@799425 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeremy Bauer 2009-07-30 19:34:33 +00:00
parent b9d609a3b0
commit 9706a82960
15 changed files with 844 additions and 22 deletions

View File

@ -19,8 +19,12 @@
package org.apache.openjpa.persistence.util;
import java.sql.Date;
import java.util.Set;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@ -32,7 +36,7 @@ public class EagerEmbed {
@Temporal(TemporalType.DATE)
private Date endDate;
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
@ -48,4 +52,5 @@ public class EagerEmbed {
public Date getEndDate() {
return endDate;
}
}

View File

@ -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.persistence.util;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Embeddable;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
@Embeddable
public class EagerEmbedRel {
@ElementCollection(fetch=FetchType.EAGER)
private Set<Integer> intVals;
@OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private Set<EagerEntity> eagerEnts;
public void setIntVals(Set<Integer> intVals) {
this.intVals = intVals;
}
public Set<Integer> getIntVals() {
return intVals;
}
public void setEagerEnts(Set<EagerEntity> eagerEnts) {
this.eagerEnts = eagerEnts;
}
public Set<EagerEntity> getEagerEnts() {
return eagerEnts;
}
}

View File

@ -18,9 +18,13 @@
*/
package org.apache.openjpa.persistence.util;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.Transient;
@ -35,6 +39,12 @@ public class EagerEntity {
@Embedded
private EagerEmbed eagerEmbed;
@Embedded
private EagerEmbedRel eagerEmbedRel;
@ElementCollection(fetch=FetchType.EAGER)
private List<EagerEmbed> eagerEmbedColl;
@Transient
private String transField;
@ -70,4 +80,20 @@ public class EagerEntity {
public String getTransField() {
return transField;
}
public void setEagerEmbedColl(List<EagerEmbed> eagerEmbedColl) {
this.eagerEmbedColl = eagerEmbedColl;
}
public List<EagerEmbed> getEagerEmbedColl() {
return eagerEmbedColl;
}
public void setEagerEmbedRel(EagerEmbedRel eagerEmbedRel) {
this.eagerEmbedRel = eagerEmbedRel;
}
public EagerEmbedRel getEagerEmbedRel() {
return eagerEmbedRel;
}
}

View File

@ -18,11 +18,17 @@
*/
package org.apache.openjpa.persistence.util;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.ElementCollection;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
@Entity
@ -36,6 +42,15 @@ public class LazyEntity {
@Embedded
private LazyEmbed lazyEmbed;
@ElementCollection(fetch=FetchType.LAZY)
private List<LazyEmbed> lazyEmbedColl;
@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
private List<RelEntity> relEntities;
@OneToOne(fetch=FetchType.LAZY)
private RelEntity relEntity;
@Transient
private String transField;
@ -71,4 +86,28 @@ public class LazyEntity {
public String getTransField() {
return transField;
}
public void setLazyEmbedColl(List<LazyEmbed> lazyEmbedColl) {
this.lazyEmbedColl = lazyEmbedColl;
}
public List<LazyEmbed> getLazyEmbedColl() {
return lazyEmbedColl;
}
public void setRelEntities(List<RelEntity> relEntities) {
this.relEntities = relEntities;
}
public List<RelEntity> getRelEntities() {
return relEntities;
}
public void setRelEntity(RelEntity relEntity) {
this.relEntity = relEntity;
}
public RelEntity getRelEntity() {
return relEntity;
}
}

View File

@ -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.persistence.util;
import java.util.Map;
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.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="MAPENT")
public class MapEntity {
@Id
@GeneratedValue
private int id;
@OneToOne(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
private MapValEntity mapValEntity;
@OneToMany(fetch=FetchType.EAGER)
private Map<MapKeyEmbed, MapValEntity> mapEntities;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setMapValEntity(MapValEntity mapValEntity) {
this.mapValEntity = mapValEntity;
}
public MapValEntity getMapValEntity() {
return mapValEntity;
}
public void setMapEntities(Map<MapKeyEmbed, MapValEntity> mapEntities) {
this.mapEntities = mapEntities;
}
public Map<MapKeyEmbed, MapValEntity> getMapEntities() {
return mapEntities;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.util;
import javax.persistence.Embeddable;
@Embeddable
public class MapKeyEmbed {
private String firstName;
private String lastName;
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getFirstName() {
return firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getLastName() {
return lastName;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.util;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="MVTABLE")
public class MapValEntity {
@Id
@GeneratedValue
private int id;
private int intVal;
@OneToOne(fetch=FetchType.EAGER, mappedBy="mapValEntity",
cascade=CascadeType.ALL)
private MapEntity mapEntity;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setIntVal(int intVal) {
this.intVal = intVal;
}
public int getIntVal() {
return intVal;
}
public void setMapEntity(MapEntity mapEntity) {
this.mapEntity = mapEntity;
}
public MapEntity getMapEntity() {
return mapEntity;
}
}

View File

@ -0,0 +1,50 @@
/*
* 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.util;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class RelEntity {
@Id
@GeneratedValue
private int id;
private String name;
public void setId(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}

View File

@ -19,15 +19,21 @@
package org.apache.openjpa.persistence.util;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.PersistenceUnitUtil;
import javax.persistence.PersistenceUtil;
import javax.persistence.spi.LoadState;
import javax.persistence.spi.PersistenceProvider;
import javax.persistence.spi.ProviderUtil;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
import org.apache.openjpa.persistence.OpenJPAPersistence;
import org.apache.openjpa.persistence.PersistenceProviderImpl;
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
@ -35,7 +41,9 @@ public class TestPersistenceUnitUtil extends SingleEMFTestCase{
public void setUp() {
setUp(CLEAR_TABLES, EagerEntity.class, LazyEmbed.class,
LazyEntity.class, EagerEmbed.class);
LazyEntity.class, EagerEmbed.class, RelEntity.class,
EagerEmbedRel.class, MapEntity.class,
MapKeyEmbed.class, MapValEntity.class);
}
/*
@ -69,6 +77,85 @@ public class TestPersistenceUnitUtil extends SingleEMFTestCase{
public void testNotLoadedEager() {
verifyIsLoadedEagerState(false);
}
/**
* Verifies the use of PersistenceUnitUtil with multiple PU's.
*/
public void testMultiplePUs() {
OpenJPAEntityManagerFactorySPI emf1 =
(OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.
createEntityManagerFactory("PUtil1",
"org/apache/openjpa/persistence/util/" +
"persistence.xml");
assertNotNull(emf1);
OpenJPAEntityManagerFactorySPI emf2 =
(OpenJPAEntityManagerFactorySPI)OpenJPAPersistence.
createEntityManagerFactory("PUtil2",
"org/apache/openjpa/persistence/util/" +
"persistence.xml");
assertNotNull(emf2);
assertNotSame(emf, emf1);
assertNotSame(emf1, emf2);
PersistenceUnitUtil puu = emf.getPersistenceUnitUtil();
PersistenceUnitUtil puu1 = emf1.getPersistenceUnitUtil();
PersistenceUnitUtil puu2 = emf2.getPersistenceUnitUtil();
assertNotSame(puu, puu1);
assertNotSame(puu, puu2);
assertNotSame(puu1, puu2);
EntityManager em = emf.createEntityManager();
EntityManager em1 = emf1.createEntityManager();
EntityManager em2 = emf2.createEntityManager();
verifyPULoadState(em, puu, puu1, puu2);
verifyPULoadState(em1, puu1, puu, puu2);
verifyPULoadState(em2, puu2, puu, puu1);
em.close();
em1.close();
em2.close();
if (emf1 != null) {
emf1.close();
}
if (emf2 != null) {
emf2.close();
}
}
private void verifyPULoadState(EntityManager em,
PersistenceUnitUtil...puu) {
EagerEntity ee = createEagerEntity();
assertEquals(false, puu[0].isLoaded(ee));
assertEquals(false, puu[0].isLoaded(ee,
"id"));
assertEquals(false, puu[1].isLoaded(ee));
assertEquals(false, puu[1].isLoaded(ee,
"id"));
assertEquals(false, puu[2].isLoaded(ee));
assertEquals(false, puu[2].isLoaded(ee,
"id"));
em.getTransaction().begin();
em.persist(ee);
em.getTransaction().commit();
assertEquals(true, puu[0].isLoaded(ee));
assertEquals(true, puu[0].isLoaded(ee,
"id"));
assertEquals(false, puu[1].isLoaded(ee));
assertEquals(false, puu[1].isLoaded(ee,
"id"));
assertEquals(false, puu[2].isLoaded(ee));
assertEquals(false, puu[2].isLoaded(ee,
"id"));
}
private void verifyIsLoadedEagerState(boolean loaded) {
@ -163,7 +250,52 @@ public class TestPersistenceUnitUtil extends SingleEMFTestCase{
em.close();
}
public void testPCMapEager() {
PersistenceUnitUtil puu = emf.getPersistenceUnitUtil();
EntityManager em = emf.createEntityManager();
MapValEntity mve = new MapValEntity();
mve.setIntVal(10);
MapKeyEmbed mke = new MapKeyEmbed();
mke.setFirstName("Jane");
mke.setLastName("Doe");
MapEntity me = new MapEntity();
assertEquals(false, puu.isLoaded(me));
assertEquals(false, puu.isLoaded(me,
"mapValEntity"));
assertEquals(false, puu.isLoaded(me,
"mapEntities"));
assertEquals(false, puu.isLoaded(mve));
// Create a circular ref
me.setMapValEntity(mve);
mve.setMapEntity(me);
HashMap<MapKeyEmbed, MapValEntity> hm =
new HashMap<MapKeyEmbed, MapValEntity>();
hm.put(mke, mve);
me.setMapEntities(hm);
em.getTransaction().begin();
em.persist(me);
em.getTransaction().commit();
assertEquals(true, puu.isLoaded(me));
assertEquals(true, puu.isLoaded(me,
"mapValEntity"));
assertEquals(true, puu.isLoaded(me,
"mapEntities"));
assertEquals(true, puu.isLoaded(mve));
em.close();
}
private EagerEntity createEagerEntity() {
EagerEntity ee = new EagerEntity();
ee.setId(new Random().nextInt());
@ -188,6 +320,10 @@ public class TestPersistenceUnitUtil extends SingleEMFTestCase{
emb.setEndDate(new Date(System.currentTimeMillis()));
emb.setStartDate(new Date(System.currentTimeMillis()));
le.setLazyEmbed(emb);
RelEntity re = new RelEntity();
re.setName("My ent");
ArrayList<RelEntity> rel = new ArrayList<RelEntity>();
rel.add(new RelEntity());
return le;
}

View File

@ -19,6 +19,8 @@
package org.apache.openjpa.persistence.util;
import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import javax.persistence.EntityManager;
@ -35,7 +37,8 @@ public class TestPersistenceUtil extends SingleEMFTestCase{
public void setUp() {
setUp(CLEAR_TABLES, EagerEntity.class, LazyEmbed.class,
LazyEntity.class, EagerEmbed.class);
LazyEntity.class, EagerEmbed.class, EagerEmbedRel.class,
RelEntity.class);
}
/*
@ -187,6 +190,11 @@ public class TestPersistenceUtil extends SingleEMFTestCase{
emb.setEndDate(new Date(System.currentTimeMillis()));
emb.setStartDate(new Date(System.currentTimeMillis()));
le.setLazyEmbed(emb);
RelEntity re = new RelEntity();
re.setName("My ent");
ArrayList<RelEntity> rel = new ArrayList<RelEntity>();
rel.add(new RelEntity());
le.setRelEntities(rel);
return le;
}

View File

@ -19,7 +19,12 @@
package org.apache.openjpa.persistence.util;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import javax.persistence.EntityManager;
import javax.persistence.spi.LoadState;
@ -33,7 +38,8 @@ public class TestProviderUtil extends SingleEMFTestCase{
public void setUp() {
setUp(CLEAR_TABLES, EagerEntity.class, LazyEmbed.class,
LazyEntity.class, EagerEmbed.class);
LazyEntity.class, EagerEmbed.class, EagerEmbedRel.class,
RelEntity.class);
}
/*
@ -72,7 +78,7 @@ public class TestProviderUtil extends SingleEMFTestCase{
private void verifyIsLoadedEagerState(LoadState state) {
ProviderUtil pu = getProviderUtil();
EntityManager em = emf.createEntityManager();
EagerEntity ee = createEagerEntity();
EagerEntity ee = createEagerEntity(true);
// Vfy LoadState is unknown for the unmanaged entity
assertEquals(LoadState.UNKNOWN, pu.isLoaded(ee));
@ -104,6 +110,10 @@ public class TestProviderUtil extends SingleEMFTestCase{
"eagerEmbed"));
assertEquals(state, pu.isLoadedWithoutReference(ee,
"eagerEmbed"));
assertEquals(state, pu.isLoadedWithReference(ee,
"eagerEmbedColl"));
assertEquals(state, pu.isLoadedWithoutReference(ee,
"eagerEmbedColl"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithReference(ee,
"transField"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithoutReference(ee,
@ -149,6 +159,11 @@ public class TestProviderUtil extends SingleEMFTestCase{
"lazyEmbed"));
assertEquals(state, pu.isLoadedWithoutReference(le,
"lazyEmbed"));
// lazyEmbedColl is lazy fetch so it should not be loaded
assertEquals(LoadState.NOT_LOADED, pu.isLoadedWithReference(le,
"lazyEmbedColl"));
assertEquals(LoadState.NOT_LOADED, pu.isLoadedWithoutReference(le,
"lazyEmbedColl"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithReference(le,
"transField"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithoutReference(le,
@ -164,7 +179,7 @@ public class TestProviderUtil extends SingleEMFTestCase{
public void testIsApplicationLoaded() {
ProviderUtil pu = getProviderUtil();
EntityManager em = emf.createEntityManager();
EagerEntity ee = createEagerEntity();
EagerEntity ee = createEagerEntity(true);
em.getTransaction().begin();
em.persist(ee);
@ -202,15 +217,30 @@ public class TestProviderUtil extends SingleEMFTestCase{
"id"));
}
private EagerEntity createEagerEntity() {
private EagerEntity createEagerEntity(boolean createRels) {
EagerEntity ee = new EagerEntity();
ee.setId(new Random().nextInt());
ee.setName("EagerEntity");
EagerEmbed emb = createEagerEmbed();
List<EagerEmbed> embcoll = createEagerEmbedColl();
ee.setEagerEmbed(emb);
ee.setEagerEmbedColl(embcoll);
if (createRels) {
EagerEmbedRel eer = createEagerEmbedRel(createRels);
ee.setEagerEmbedRel(eer);
}
ee.setEagerEmbedRel(null);
return ee;
}
private List<EagerEmbed> createEagerEmbedColl() {
ArrayList<EagerEmbed> al = new ArrayList<EagerEmbed>();
for (int i = 0; i < 5; i++) {
al.add(createEagerEmbed());
}
return al;
}
private EagerEmbed createEagerEmbed() {
EagerEmbed emb = new EagerEmbed();
emb.setEndDate(new Date(System.currentTimeMillis()));
@ -218,17 +248,49 @@ public class TestProviderUtil extends SingleEMFTestCase{
return emb;
}
private EagerEmbedRel createEagerEmbedRel(boolean createRels) {
EagerEmbedRel emb = new EagerEmbedRel();
Set<EagerEntity> ee = new HashSet<EagerEntity>();
if (createRels) {
ee.add(createEagerEntity(false));
ee.add(createEagerEntity(false));
ee.add(createEagerEntity(false));
}
Set<Integer> ints = new HashSet<Integer>();
for (int i = 0; i < 12; i++) {
ints.add(new Integer(i));
}
emb.setIntVals(ints);
emb.setEagerEnts(ee);
return emb;
}
private LazyEntity createLazyEntity() {
LazyEntity le = new LazyEntity();
le.setId(new Random().nextInt());
le.setName("LazyEntity");
LazyEmbed emb = createLazyEmbed();
le.setLazyEmbed(emb);
le.setLazyEmbedColl(createLazyEmbedColl());
return le;
}
private LazyEmbed createLazyEmbed() {
LazyEmbed emb = new LazyEmbed();
emb.setEndDate(new Date(System.currentTimeMillis()));
emb.setStartDate(new Date(System.currentTimeMillis()));
le.setLazyEmbed(emb);
return le;
return emb;
}
private List<LazyEmbed> createLazyEmbedColl() {
ArrayList<LazyEmbed> al = new ArrayList<LazyEmbed>();
for (int i = 0; i < 5; i++) {
al.add(createLazyEmbed());
}
return al;
}
private void assertEagerLoadState(ProviderUtil pu, Object ent,
LoadState state) {
assertEquals(state, pu.isLoaded(ent));
@ -244,6 +306,10 @@ public class TestProviderUtil extends SingleEMFTestCase{
"eagerEmbed"));
assertEquals(state, pu.isLoadedWithoutReference(ent,
"eagerEmbed"));
assertEquals(state, pu.isLoadedWithReference(ent,
"eagerEmbedRel"));
assertEquals(state, pu.isLoadedWithoutReference(ent,
"eagerEmbedRel"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithReference(ent,
"transField"));
assertEquals(LoadState.UNKNOWN, pu.isLoadedWithoutReference(ent,

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="2.0">
<persistence-unit name="PUtil1">
<class>org.apache.openjpa.persistence.util.EagerEntity</class>
<class>org.apache.openjpa.persistence.util.LazyEmbed</class>
<class>org.apache.openjpa.persistence.util.LazyEntity</class>
<class>org.apache.openjpa.persistence.util.EagerEmbed</class>
<class>org.apache.openjpa.persistence.util.RelEntity</class>
<class>org.apache.openjpa.persistence.util.EagerEmbedRel</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
</properties>
</persistence-unit>
<persistence-unit name="PUtil2">
<class>org.apache.openjpa.persistence.util.EagerEntity</class>
<class>org.apache.openjpa.persistence.util.LazyEmbed</class>
<class>org.apache.openjpa.persistence.util.LazyEntity</class>
<class>org.apache.openjpa.persistence.util.EagerEmbed</class>
<class>org.apache.openjpa.persistence.util.RelEntity</class>
<class>org.apache.openjpa.persistence.util.EagerEmbedRel</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
</properties>
</persistence-unit>
</persistence>

View File

@ -20,6 +20,8 @@ package org.apache.openjpa.persistence;
import java.util.BitSet;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import javax.persistence.spi.LoadState;
@ -29,6 +31,9 @@ import org.apache.openjpa.kernel.AbstractBrokerFactory;
import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.ValueMetaData;
import org.apache.openjpa.util.ImplHelper;
public class OpenJPAPersistenceUtil {
@ -95,9 +100,14 @@ public class OpenJPAPersistenceUtil {
// Cycle through all brokers managed by this factory.
Broker[] brokerArr = brokers.toArray(new Broker[brokers.size()]);
for (Broker broker : brokerArr) {
if (broker != null && !broker.isClosed() &&
broker.isPersistent(entity))
return true;
if (broker != null && !broker.isClosed())
if (ImplHelper.isManageable(entity)) {
PersistenceCapable pc = (PersistenceCapable)entity;
// Vfy this broker is managing the entity
if (pc.pcGetGenericContext() == broker) {
return true;
}
}
}
}
return false;
@ -146,13 +156,14 @@ public class OpenJPAPersistenceUtil {
}
StateManager sm = pc.pcGetStateManager();
if (sm != null && sm instanceof OpenJPAStateManager) {
return isLoaded((OpenJPAStateManager)sm, attr);
return isLoaded((OpenJPAStateManager)sm, attr, null);
}
}
return LoadState.UNKNOWN;
}
private static LoadState isLoaded(OpenJPAStateManager sm, String attr) {
private static LoadState isLoaded(OpenJPAStateManager sm, String attr,
HashSet<OpenJPAStateManager> pcs) {
boolean isLoaded = true;
BitSet loadSet = sm.getLoaded();
if (attr != null) {
@ -168,15 +179,160 @@ public class OpenJPAPersistenceUtil {
}
FieldMetaData[] fmds = sm.getMetaData().getFields();
// Check load state of all persistent eager fetch attributes
for (FieldMetaData fmd : fmds) {
if (fmd.isInDefaultFetchGroup()) {
if (!loadSet.get(fmd.getIndex())) {
isLoaded = false;
break;
if (fmds != null && fmds.length > 0) {
pcs = addToLoadSet(pcs, sm);
for (FieldMetaData fmd : fmds) {
if (fmd.isInDefaultFetchGroup()) {
if (!isLoadedField(sm, fmd, pcs)) {
isLoaded = false;
break;
}
}
// TODO: Complete contract for collections
}
}
pcs.remove(sm);
}
return isLoaded ? LoadState.LOADED : LoadState.NOT_LOADED;
}
private static HashSet<OpenJPAStateManager> addToLoadSet(
HashSet<OpenJPAStateManager> pcs, OpenJPAStateManager sm) {
if (pcs == null) {
pcs = new HashSet<OpenJPAStateManager>();
}
pcs.add(sm);
return pcs;
}
private static boolean isLoadedField(OpenJPAStateManager sm,
FieldMetaData fmd, HashSet<OpenJPAStateManager> pcs) {
BitSet loadSet = sm.getLoaded();
// Simple load state check for the field
if (!loadSet.get(fmd.getIndex()))
return false;
Object field = sm.fetchField(fmd.getIndex(), false);
// Get the state manager for the field, if it is a PC
OpenJPAStateManager ofsm = getStateManager(field);
// Prevent circular load state evaluation for this sm.
if (ofsm != null && pcs.contains(ofsm))
return true;
// If a collection type, determine if it is loaded
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.COLLECTION:
return isLoadedCollection(sm, fmd.getElement(),
(Collection<?>)field, pcs);
case JavaTypes.MAP:
return isLoadedMap(sm, fmd,
(Map<?,?>)field, pcs);
case JavaTypes.ARRAY:
return isLoadedArray(sm, fmd.getElement(),
(Object[])field, pcs);
}
// If other PC type, determine if it is loaded
if (ofsm != null && fmd.isDeclaredTypePC()) {
return isLoaded(ofsm, null, pcs) ==
LoadState.LOADED;
}
return true;
}
private static boolean isLoadedCollection(OpenJPAStateManager sm,
ValueMetaData vmd, Collection<?> coll, HashSet<OpenJPAStateManager> pcs) {
// This field passed the load state check in isLoadedField, so
// if any of these conditions are true the collection is loaded.
if (sm == null || coll == null || coll.size() == 0) {
return true;
}
// Convert to array to prevent concurrency issues
Object[] arr = coll.toArray();
return isLoadedArray(sm, vmd, arr, pcs);
}
private static boolean isLoadedArray(OpenJPAStateManager sm,
ValueMetaData vmd, Object[] arr,
HashSet<OpenJPAStateManager> pcs) {
// This field passed the load state check in isLoadedField, so
// if any of these conditions are true the array is loaded.
if (sm == null || arr == null || arr.length == 0) {
return true;
}
// Not a collection of PC's
if (!vmd.isDeclaredTypePC()) {
return true;
}
for (Object pc : arr) {
OpenJPAStateManager esm = getStateManager(pc);
if (esm == null) {
return true;
}
if (!(isLoaded(esm, null, pcs) == LoadState.LOADED))
return false;
}
return true;
}
private static boolean isLoadedMap(OpenJPAStateManager sm,
FieldMetaData fmd, Map<?,?> map, HashSet<OpenJPAStateManager> pcs) {
// This field passed the load state check in isLoadedField, so
// if any of these conditions are true the map is loaded.
if (sm == null || map == null || map.size() == 0) {
return true;
}
boolean keyIsPC = fmd.getKey().isDeclaredTypePC();
boolean valIsPC = fmd.getElement().isDeclaredTypePC();
// Map is does not contain PCs in either keys or values
if (!(keyIsPC || valIsPC)) {
return true;
}
Object[] arr = map.keySet().toArray();
for (Object key : arr) {
if (keyIsPC) {
OpenJPAStateManager ksm = getStateManager(key);
if (ksm == null) {
return true;
}
if (!(isLoaded(ksm, null, pcs) == LoadState.LOADED))
return false;
}
if (valIsPC) {
Object value = map.get(key);
OpenJPAStateManager vsm = getStateManager(value);
if (vsm == null) {
return true;
}
if (!(isLoaded(vsm, null, pcs) == LoadState.LOADED))
return false;
}
}
return true;
}
private static OpenJPAStateManager getStateManager(Object obj) {
if (obj == null || !(obj instanceof PersistenceCapable)) {
return null;
}
PersistenceCapable pc = (PersistenceCapable)obj;
StateManager sm = pc.pcGetStateManager();
if (sm == null || !(sm instanceof OpenJPAStateManager)) {
return null;
}
return (OpenJPAStateManager)sm;
}
}

View File

@ -427,4 +427,44 @@ an obvious reason to create and close multiple <classname>EntityManagerFactory
IllegalStateException</classname>.
</para>
</section>
<section id="jpa_overview_emfactory_puutil">
<title>
PersistenceUnitUtil
</title>
<indexterm zone="jpa_overview_emfactory_puutil">
<primary>
EntityManagerFactory
</primary>
<secondary>
util
</secondary>
</indexterm>
<programlisting>
public PersistenceUnitUtil getPersistenceUnitUtil();
</programlisting>
<para>
The <classname>EntityManagerFactory</classname> method
<methodname>getPersistenceUnitUtil</methodname> to provide access to a
<classname>PersistenceUnitUtil</classname> utility. <classname>PersistenceUnitUtil</classname>
can be used to obtain the identity of a managed object and determine the load
state of the entity or one of its attributes. If the object is not
managed by one of the entity managers created from the entity manager factory
from which the utility was obtained, the <methodname>getIdentifier</methodname> method will
return null and the <methodname>isLoaded</methodname> methods will return false.
<programlisting>
EntityManagerFactory emf = Persistence.createEntityManagerFactory();
PersistenceUnitUtil puUtil = emf.getPersistenceUnitUtil();
if (puUtil.getIdentifier(deptEntity) == null) {
throw new Exception("Identity is not valid.");
}
if (!puUtil.isLoaded(deptEntity, "employees")) {
throw new Exception("Employees not loaded.")
}
</programlisting>
</para>
</section>
</chapter>

View File

@ -75,6 +75,7 @@ EntityManagerFactory</classname> objects in a vendor-neutral fashion.
<programlisting>
public static EntityManagerFactory createEntityManagerFactory(String name);
public static EntityManagerFactory createEntityManagerFactory(String name, Map props);
public static PersistenceUtil getPersistenceUtil();
</programlisting>
<para>
Each <methodname>createEntityManagerFactory</methodname> method searches the
@ -93,6 +94,18 @@ the <filename>conf</filename> directory, you could place an <classname>
EntityManagerFactory</classname> definition in <filename>
conf/META-INF/persistence.xml</filename>.
</para>
<para>
The <methodname>getPersistenceUtil</methodname> method returns a PersistenceUtil
interface that can be used to determine whether an entity or attribute of an
entity is loaded.
</para>
<programlisting>
PersistenceUtil pUtil = Persistence.getPersistenceUtil();
if (!pUtil.isLoaded(myEntity)) {
loadEntity(myEntity);
}
</programlisting>
<section id="jpa_overview_persistence_xml">
<title>
persistence.xml