From 2a6887d4c0a839e9aeb1d1dd45a8d8ca155fa983 Mon Sep 17 00:00:00 2001 From: Michael Dick Date: Thu, 20 Sep 2007 18:12:18 +0000 Subject: [PATCH] OPENJPA-357 OPENJPA-358 git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/1.0.x@577846 13f79535-47bb-0310-9956-ffa450edef68 --- .../kernel/FetchConfigurationImpl.java | 4 +- .../org/apache/openjpa/meta/FetchGroup.java | 40 ++++++++++++++++++- .../AnnotationPersistenceMetaDataParser.java | 36 ++++++++++++++++- .../openjpa/persistence/localizer.properties | 4 ++ 4 files changed, 81 insertions(+), 3 deletions(-) diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java index f8e662b4c..0975f875f 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/FetchConfigurationImpl.java @@ -604,6 +604,8 @@ public class FetchConfigurationImpl int cur; for (int i = 0; max != FetchGroup.DEPTH_INFINITE && i < groups.length; i++) { + // ignore custom groups that are inactive in this configuration + if (!this.hasFetchGroup(groups[i])) continue; cur = meta.getFetchGroup(groups[i]).getRecursionDepth(fm); if (cur == FetchGroup.DEPTH_INFINITE || cur > max) max = cur; @@ -625,7 +627,7 @@ public class FetchConfigurationImpl return avail; return Math.min(max, avail); } - + /** * Return the relation type of the given field. */ diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FetchGroup.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FetchGroup.java index 400b3c88f..cd7c86da6 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FetchGroup.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/FetchGroup.java @@ -20,10 +20,13 @@ package org.apache.openjpa.meta; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.ObjectUtils; @@ -74,6 +77,7 @@ public class FetchGroup private final ClassMetaData _meta; private final boolean _readOnly; private List _includes; + private Set _containedBy; private Map _depths; private Boolean _postLoad; @@ -105,6 +109,9 @@ public class FetchGroup if (fg._includes != null) for (Iterator itr = fg._includes.iterator(); itr.hasNext();) addDeclaredInclude((String) itr.next()); + if (fg._containedBy != null) + this._containedBy = new HashSet(fg._containedBy); + if (fg._depths != null) { Map.Entry entry; for (Iterator itr = fg._depths.entrySet().iterator(); @@ -152,7 +159,7 @@ public class FetchGroup if (_includes != null) { if (_includes.contains(fgName)) return true; - if (recurse) { + if (recurse && _meta!=null) { FetchGroup fg; for (Iterator i = _includes.iterator(); i.hasNext();) { fg = _meta.getFetchGroup((String) i.next()); @@ -172,6 +179,37 @@ public class FetchGroup } return false; } + + /** + * Adds this receiver as one of the included fetch groups of the given + * parent. + * The parent fecth group will include this receiver as a side-effect of + * this call. + * + * @see #includes(String, boolean) + * @see #addDeclaredInclude(String) + * + * @return true if given parent is a new addition. false othrwise. + * @since 1.1.1 + */ + public boolean addContainedBy(FetchGroup parent) { + parent.addDeclaredInclude(this.getName()); + if (_containedBy==null) + _containedBy = new HashSet(); + return _containedBy.add(parent.getName()); + } + + /** + * Gets the name of the fetch groups in which this receiver has been + * included. + * + * @see #addContainedBy(FetchGroup) + * @since 1.1.1 + */ + public Set getContainedBy() { + return (_containedBy == null) ? Collections.EMPTY_SET : + Collections.unmodifiableSet(_containedBy); + } /** * Return the fetch group names declared included by this group. diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java index e549bc430..e4e8b9bbe 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/AnnotationPersistenceMetaDataParser.java @@ -109,6 +109,8 @@ import org.apache.openjpa.util.ImplHelper; import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.MetaDataException; import org.apache.openjpa.util.UnsupportedException; +import org.apache.openjpa.util.UserException; + import serp.util.Numbers; import serp.util.Strings; @@ -875,6 +877,14 @@ public class AnnotationPersistenceMetaDataParser /** * Create fetch groups. + * If FetchGroup A includes FetchGroup B, then a bi-link is set between + * A and B. Both A and B must be declared in the same Class. + *
+ * Call {@link #parseFetchAttribute(ClassMetaData, + * org.apache.openjpa.meta.FetchGroup, FetchAttribute) only after the + * bi-links have been established, because a field f will not only add the + * fetch group A which explictly includes f to its custom fetch groups but + * also will also add any fetch group B that includes A. */ private void parseFetchGroups(ClassMetaData meta, FetchGroup... groups) { org.apache.openjpa.meta.FetchGroup fg; @@ -885,12 +895,33 @@ public class AnnotationPersistenceMetaDataParser fg = meta.addDeclaredFetchGroup(group.name()); if (group.postLoad()) fg.setPostLoad(true); - for (String s : group.fetchGroups()) + for (String s : group.fetchGroups()) { fg.addDeclaredInclude(s); + } + } + // Add the parent-child style bi-links between fetch groups in a + // separate pass. + for (FetchGroup group:groups) { + fg = meta.getFetchGroup(group.name()); + String[] includedFetchGropNames = fg.getDeclaredIncludes(); + for (String includedFectchGroupName:includedFetchGropNames) { + org.apache.openjpa.meta.FetchGroup child = + meta.getFetchGroup(includedFectchGroupName); + if (child == null) + throw new UserException(_loc.get("missing-included-fg", + meta.getDescribedType().getName(), fg.getName(), + includedFectchGroupName)); + child.addContainedBy(fg); + } + } + + for (FetchGroup group : groups) { + fg = meta.getFetchGroup(group.name()); for (FetchAttribute attr : group.attributes()) parseFetchAttribute(meta, fg, attr); } } + /** * Set a field's fetch group. @@ -904,6 +935,9 @@ public class AnnotationPersistenceMetaDataParser meta, attr.name())); field.setInFetchGroup(fg.getName(), true); + Set parentFetchGroups = fg.getContainedBy(); + for (Object parentFetchGroup:parentFetchGroups) + field.setInFetchGroup(parentFetchGroup.toString(), true); if (attr.recursionDepth() != Integer.MIN_VALUE) fg.setRecursionDepth(field, attr.recursionDepth()); } diff --git a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties index c276ef84e..b19b4774b 100644 --- a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties +++ b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties @@ -59,6 +59,9 @@ unnamed-fg: "{0}" declares an unnamed fetch group. All fetch groups \ bad-fg-field: Fetch group "{0}" in type "{1}" includes field "{2}", but \ this field is not declared in "{1}", or is not persistent. Currently, \ OpenJPA only supports declared fields in fetch groups. +missing-included-fg:"{0}" declares a fecth group "{1}" includes "{2}". But \ + the included fetch group "{2}" can not be found in "{0}". Currently, all \ + included fetch groups must be declared within the same entity scope. not-update-delete-query: Cannot perform an update or delete operation \ on select query: "{0}". not-select-query: Cannot perform a select on update or delete query: "{0}". @@ -141,3 +144,4 @@ EntityManagerFactory-cat: Persistence.Advanced EntityManagerFactory-displayorder: 50 EntityManagerFactory-expert: true EntityManagerFactory-interface: org.apache.openjpa.persistence.EntityManagerFactoryImpl +