FetchPlan with recursive scheme.

- modified select building and load cycles in JDBCStoreManager with FetchState traversal 
- loadAll(), findAll() methods reverted to their method signature with FetchConfiguration instead of FetchState
- StateManager.postLoad checks for fetch group with postload set to true 

git-svn-id: https://svn.apache.org/repos/asf/incubator/openjpa/trunk@425312 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Pinaki Poddar 2006-07-25 07:10:26 +00:00
parent 98e8533cb0
commit 884ff1b863
24 changed files with 661 additions and 610 deletions

View File

@ -441,10 +441,7 @@ public class JDBCStoreManager
public boolean load(OpenJPAStateManager sm, BitSet fields, public boolean load(OpenJPAStateManager sm, BitSet fields,
FetchState fetchState, int lockLevel, Object context) { FetchState fetchState, int lockLevel, Object context) {
JDBCFetchState jfetchState = (fetchState == null) ? (JDBCFetchState) getFetchConfiguration() JDBCFetchState jfetchState = (JDBCFetchState) fetchState;
.newFetchState()
: (JDBCFetchState) fetchState;
JDBCFetchConfiguration jfetch = getFetchConfiguration(jfetchState); JDBCFetchConfiguration jfetch = getFetchConfiguration(jfetchState);
// get a connection, or reuse current one // get a connection, or reuse current one
@ -492,9 +489,10 @@ public class JDBCStoreManager
// now allow the fields to load themselves individually too // now allow the fields to load themselves individually too
for (int i = 0, len = fields.length(); i < len; i++) for (int i = 0, len = fields.length(); i < len; i++)
if (fields.get(i) && !sm.getLoaded().get(i)) if (fields.get(i) && !sm.getLoaded().get(i)) {
mapping.getFieldMapping(i).load(sm, this, jfetchState); FieldMapping fm = mapping.getFieldMapping(i);
fm.load(sm, this, (JDBCFetchState)jfetchState.traverse(fm));
}
mapping.getVersion().afterLoad(sm, this); mapping.getVersion().afterLoad(sm, this);
return true; return true;
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
@ -514,8 +512,8 @@ public class JDBCStoreManager
} }
public Collection loadAll(Collection sms, PCState state, int load, public Collection loadAll(Collection sms, PCState state, int load,
FetchState fetchState, Object context) { FetchConfiguration fetch, Object context) {
return ImplHelper.loadAll(sms, this, state, load, fetchState, context); return ImplHelper.loadAll(sms, this, state, load, fetch, context);
} }
public void beforeStateChange(OpenJPAStateManager sm, PCState fromState, public void beforeStateChange(OpenJPAStateManager sm, PCState fromState,
@ -829,23 +827,25 @@ public class JDBCStoreManager
for (int i = 0; i < fms.length; i++) { for (int i = 0; i < fms.length; i++) {
if (fms[i].isPrimaryKey() || sm.getLoaded().get(fms[i].getIndex())) if (fms[i].isPrimaryKey() || sm.getLoaded().get(fms[i].getIndex()))
continue; continue;
// check for eager result, and if not present do standard load // check for eager result, and if not present do standard load
eres = res.getEager(fms[i]); eres = res.getEager(fms[i]);
res.startDataRequest(fms[i]); res.startDataRequest(fms[i]);
try { try {
if (eres == res) { if (eres == res) {
if (eagerToMany == null && fms[i].isEagerSelectToMany()) if (eagerToMany == null && fms[i].isEagerSelectToMany())
eagerToMany = fms[i]; eagerToMany = fms[i];
else else
fms[i].loadEagerJoin(sm, this, fetchState, res); fms[i].loadEagerJoin(sm, this,
(JDBCFetchState)fetchState.traverse(fms[i]), res);
} else if (eres != null) { } else if (eres != null) {
processed = fms[i].loadEagerParallel(sm, this, fetchState, processed = fms[i].loadEagerParallel(sm, this,
eres); (JDBCFetchState)fetchState.traverse(fms[i]), eres);
if (processed != eres) if (processed != eres)
res.putEager(fms[i], processed); res.putEager(fms[i], processed);
} else } else
fms[i].load(sm, this, fetchState, res); fms[i].load(sm, this,
(JDBCFetchState)fetchState.traverse(fms[i]), res);
} finally { } finally {
res.endDataRequest(); res.endDataRequest();
} }
@ -931,11 +931,11 @@ public class JDBCStoreManager
int jtype; int jtype;
int mode; int mode;
for (int i = 0; i < fms.length; i++) { for (int i = 0; i < fms.length; i++) {
if (!requiresSelect(fms[i], sm, fields, fetchState))
continue;
mode = fms[i].getEagerFetchMode(); mode = fms[i].getEagerFetchMode();
if (mode == fetch.EAGER_NONE) if (mode == fetch.EAGER_NONE)
continue; continue;
if (!requiresSelect(fms[i], sm, fields, fetchState))
continue;
// try to select with join first // try to select with join first
jtype = (fms[i].getNullValue() == fms[i].NULL_EXCEPTION) ? sel.EAGER_INNER jtype = (fms[i].getNullValue() == fms[i].NULL_EXCEPTION) ? sel.EAGER_INNER
@ -985,7 +985,7 @@ public class JDBCStoreManager
if (sm != null && sm.getPCState() != PCState.TRANSIENT if (sm != null && sm.getPCState() != PCState.TRANSIENT
&& sm.getLoaded().get(fm.getIndex())) && sm.getLoaded().get(fm.getIndex()))
return false; return false;
return fetchState.requiresSelect(fm, true); return fetchState.requiresFetch(fm);
} }
/** /**
@ -1059,17 +1059,19 @@ public class JDBCStoreManager
esel = sel.getEager(fms[i]); esel = sel.getEager(fms[i]);
if (esel != null) { if (esel != null) {
if (esel == sel) if (esel == sel)
fms[i].selectEagerJoin(sel, sm, this, fetchState, eager); fms[i].selectEagerJoin(sel, sm, this,
(JDBCFetchState)fetchState.traverse(fms[i]), eager);
else else
fms[i].selectEagerParallel(esel, sm, this, fetchState, fms[i].selectEagerParallel(esel, sm, this,
eager); (JDBCFetchState)fetchState.traverse(fms[i]), eager);
seld = Math.max(0, seld); seld = Math.max(0, seld);
} else if (requiresSelect(fms[i], sm, fields, fetchState)) { } else if (requiresSelect(fms[i], sm, fields, fetchState)) {
fseld = fms[i].select(sel, sm, this, fetchState, eager); fseld = fms[i].select(sel, sm, this,
(JDBCFetchState)fetchState.traverse(fms[i]), eager);
seld = Math.max(fseld, seld); seld = Math.max(fseld, seld);
} else if (optSelect(fms[i], sel, sm, fetchState)) { } else if (optSelect(fms[i], sel, sm, fetchState)) {
fseld = fms[i].select(sel, sm, this, fetchState, fseld = fms[i].select(sel, sm, this,
fetch.EAGER_NONE); (JDBCFetchState)fetchState.traverse(fms[i]), fetch.EAGER_NONE);
// don't upgrade seld to > 0 based on these fields, since // don't upgrade seld to > 0 based on these fields, since
// they're not in the calculated field set // they're not in the calculated field set
@ -1100,7 +1102,7 @@ public class JDBCStoreManager
.getLoaded().get(fm.getIndex())) .getLoaded().get(fm.getIndex()))
&& fm.supportsSelect(sel, sel.TYPE_TWO_PART, sm, this, && fm.supportsSelect(sel, sel.TYPE_TWO_PART, sm, this,
getFetchConfiguration(fetchState)) > 0 getFetchConfiguration(fetchState)) > 0
&& fetchState.requiresSelect(fm, true); && fetchState.requiresFetch(fm);
} }
/** /**
@ -1141,12 +1143,15 @@ public class JDBCStoreManager
fms = subMappings[i].getDefinedFieldMappings(); fms = subMappings[i].getDefinedFieldMappings();
for (int j = 0; j < fms.length; j++) { for (int j = 0; j < fms.length; j++) {
// make sure in one of configured fetch groups // make sure in one of configured fetch groups
if (!fms[j].isInDefaultFetchGroup() if (fetchState.requiresFetch(fms[j])
&& !fetch.hasFetchGroup(fms[j].getFetchGroups()) || fms[j].supportsSelect(sel, sel.TYPE_TWO_PART, sm, this, fetch) <= 0)
&& !fetch.hasField(fms[j].getFullName()) continue;
&& (fms[j].isDefaultFetchGroupExplicit() || fms[j] // if (!fms[j].isInDefaultFetchGroup()
.supportsSelect(sel, sel.TYPE_TWO_PART, sm, this, fetch) <= 0)) // && !fetch.hasAnyFetchGroup(fms[j].getFetchGroups())
continue; // && !fetch.hasField(fms[j].getFullName())
// && (fms[j].isDefaultFetchGroupExplicit() || fms[j]
// .supportsSelect(sel, sel.TYPE_TWO_PART, sm, this, fetch) <= 0))
// continue;
// if we can join to the subclass, do so; much better chance // if we can join to the subclass, do so; much better chance
// that the field will be able to select itself without joins // that the field will be able to select itself without joins
@ -1159,9 +1164,10 @@ public class JDBCStoreManager
// if can select with tables already selected, do it // if can select with tables already selected, do it
if (fms[j].supportsSelect(sel, sel.TYPE_JOINLESS, sm, this, if (fms[j].supportsSelect(sel, sel.TYPE_JOINLESS, sm, this,
fetch) > 0) fetch) > 0 && fetchState.requiresFetch(fms[j]))
fms[j] fms[j].select(sel, null, this,
.select(sel, null, this, fetchState, fetch.EAGER_NONE); (JDBCFetchState)fetchState.traverse(fms[j]),
fetch.EAGER_NONE);
} }
} }
} }

View File

@ -92,7 +92,7 @@ public class PagingResultObjectProvider
BitSet paged = null; BitSet paged = null;
for (int i = 0; i < fms.length; i++) { for (int i = 0; i < fms.length; i++) {
if (fetchState != null if (fetchState != null
&& !fetchState.requiresSelect(fms[i], false)) && !fetchState.requiresFetch(fms[i]))
continue; continue;
if (fms[i].supportsSelect(sel, sel.EAGER_PARALLEL, null, store, if (fms[i].supportsSelect(sel, sel.EAGER_PARALLEL, null, store,

View File

@ -233,8 +233,8 @@ public abstract class AbstractStoreManager
* advantageous. * advantageous.
*/ */
public Collection loadAll(Collection sms, PCState state, int load, public Collection loadAll(Collection sms, PCState state, int load,
FetchState fetchState, Object context) { FetchConfiguration fetch, Object context) {
return ImplHelper.loadAll(sms, this, state, load, fetchState, context); return ImplHelper.loadAll(sms, this, state, load, fetch, context);
} }
/** /**

View File

@ -408,12 +408,9 @@ public class DataCacheStoreManager
} }
public Collection loadAll(Collection sms, PCState state, int load, public Collection loadAll(Collection sms, PCState state, int load,
FetchState fetchState, Object edata) { FetchConfiguration fetch, Object edata) {
FetchConfiguration fetch = (fetchState == null)
? _ctx.getFetchConfiguration()
: fetchState.getFetchConfiguration();
if (isLocking(fetch)) if (isLocking(fetch))
return super.loadAll(sms, state, load, fetchState, edata); return super.loadAll(sms, state, load, fetch, edata);
Map unloaded = null; Map unloaded = null;
OpenJPAStateManager sm; OpenJPAStateManager sm;
@ -435,7 +432,7 @@ public class DataCacheStoreManager
//### the 'data.type' access here probably needs //### the 'data.type' access here probably needs
//### to be addressed for bug 511 //### to be addressed for bug 511
sm.initialize(data.getType(), state); sm.initialize(data.getType(), state);
data.load(sm, fetchState, edata); data.load(sm, fetch.newFetchState(), edata);
} else } else
unloaded = addUnloaded(sm, null, unloaded); unloaded = addUnloaded(sm, null, unloaded);
} else if (load != FORCE_LOAD_NONE } else if (load != FORCE_LOAD_NONE
@ -443,6 +440,7 @@ public class DataCacheStoreManager
data = cache.get(sm.getObjectId()); data = cache.get(sm.getObjectId());
if (data != null) { if (data != null) {
// load unloaded fields // load unloaded fields
FetchState fetchState = fetch.newFetchState();
fields = sm.getUnloaded(fetchState); fields = sm.getUnloaded(fetchState);
data.load(sm, fields, fetchState, edata); data.load(sm, fields, fetchState, edata);
if (fields.length() > 0) if (fields.length() > 0)
@ -458,7 +456,7 @@ public class DataCacheStoreManager
// load with delegate // load with delegate
Collection failed = super.loadAll(unloaded.keySet(), state, load, Collection failed = super.loadAll(unloaded.keySet(), state, load,
fetchState, edata); fetch, edata);
if (!_ctx.getPopulateDataCache()) if (!_ctx.getPopulateDataCache())
return failed; return failed;

View File

@ -575,7 +575,7 @@ public class PCDataGenerator
code.invokevirtual().setMethod(FieldMetaData.class, code.invokevirtual().setMethod(FieldMetaData.class,
"getFetchGroups", Set.class, null); "getFetchGroups", Set.class, null);
code.invokeinterface().setMethod code.invokeinterface().setMethod
(FetchConfiguration.class, "hasFetchGroup", (FetchConfiguration.class, "hasAnyFetchGroup",
boolean.class, new Class[]{ Set.class }); boolean.class, new Class[]{ Set.class });
JumpInstruction ifins = code.ifne(); JumpInstruction ifins = code.ifne();
code.aload().setLocal(fetch); code.aload().setLocal(fetch);

View File

@ -694,11 +694,13 @@ public class BrokerImpl
int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED; int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED;
if (!validate) if (!validate)
flags |= OID_NOVALIDATE; flags |= OID_NOVALIDATE;
return find(oid, null, null, null, flags, call); return find(oid, _fc.newFetchState (), null, null, flags, call);
} }
public Object find(Object oid, FetchState fetchState, BitSet exclude, public Object find(Object oid, FetchState fetchState, BitSet exclude,
Object edata, int flags) { Object edata, int flags) {
if (fetchState == null)
fetchState = _fc.newFetchState ();
return find(oid, fetchState, exclude, edata, flags, null); return find(oid, fetchState, exclude, edata, flags, null);
} }
@ -717,8 +719,6 @@ public class BrokerImpl
} }
beginOperation(true); beginOperation(true);
if (fetchState == null)
fetchState = _fc.newFetchState();
try { try {
assertNontransactionalRead(); assertNontransactionalRead();
@ -842,18 +842,18 @@ public class BrokerImpl
int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED; int flags = OID_COPY | OID_ALLOW_NEW | OID_NODELETED;
if (!validate) if (!validate)
flags |= OID_NOVALIDATE; flags |= OID_NOVALIDATE;
return findAll(oids, null, null, null, flags, call); return findAll(oids, _fc, null, null, flags, call);
} }
public Object[] findAll(Collection oids, FetchState fetchState, public Object[] findAll(Collection oids, FetchConfiguration fetch,
BitSet exclude, Object edata, int flags) { BitSet exclude, Object edata, int flags) {
return findAll(oids, fetchState, exclude, edata, flags, null); return findAll(oids, fetch, exclude, edata, flags, null);
} }
/** /**
* Internal finder. * Internal finder.
*/ */
protected Object[] findAll(Collection oids, FetchState fetchState, protected Object[] findAll(Collection oids, FetchConfiguration fetch,
BitSet exclude, Object edata, int flags, FindCallbacks call) { BitSet exclude, Object edata, int flags, FindCallbacks call) {
// throw any exceptions for null oids up immediately // throw any exceptions for null oids up immediately
if (oids == null) if (oids == null)
@ -867,9 +867,6 @@ public class BrokerImpl
_loading = new HashMap((int) (oids.size() * 1.33 + 1)); _loading = new HashMap((int) (oids.size() * 1.33 + 1));
if (call == null) if (call == null)
call = this; call = this;
if (fetchState == null)
fetchState = _fc.newFetchState();
FetchConfiguration fetch = fetchState.getFetchConfiguration();
beginOperation(true); beginOperation(true);
try { try {
assertNontransactionalRead(); assertNontransactionalRead();
@ -915,7 +912,7 @@ public class BrokerImpl
PCState state = (transState) ? PCState.PCLEAN PCState state = (transState) ? PCState.PCLEAN
: PCState.PNONTRANS; : PCState.PNONTRANS;
Collection failed = _store.loadAll(load, state, Collection failed = _store.loadAll(load, state,
StoreManager.FORCE_LOAD_NONE, fetchState, edata); StoreManager.FORCE_LOAD_NONE, _fc, edata);
// set failed instances to null // set failed instances to null
if (failed != null && !failed.isEmpty()) { if (failed != null && !failed.isEmpty()) {
@ -937,8 +934,8 @@ public class BrokerImpl
sm = (StateManagerImpl) _loading.get(oid); sm = (StateManagerImpl) _loading.get(oid);
if (sm != null && requiresLoad(sm, true, edata, flags)) { if (sm != null && requiresLoad(sm, true, edata, flags)) {
try { try {
sm.load(fetchState, StateManagerImpl.LOAD_FGS, exclude, sm.load(fetch.newFetchState(), StateManagerImpl.LOAD_FGS,
edata, false); exclude, edata, false);
if (active) { if (active) {
_lm.lock(sm, level, fetch.getLockTimeout(), edata); _lm.lock(sm, level, fetch.getLockTimeout(), edata);
sm.readLocked(level, fetch.getWriteLockLevel()); sm.readLocked(level, fetch.getWriteLockLevel());
@ -2687,7 +2684,7 @@ public class BrokerImpl
// refresh all // refresh all
if (load != null) { if (load != null) {
Collection failed = _store.loadAll(load, null, Collection failed = _store.loadAll(load, null,
_store.FORCE_LOAD_REFRESH, _fc.newFetchState(), null); _store.FORCE_LOAD_REFRESH, _fc, null);
if (failed != null && !failed.isEmpty()) if (failed != null && !failed.isEmpty())
exceps = add(exceps, newObjectNotFoundException(failed)); exceps = add(exceps, newObjectNotFoundException(failed));
@ -2812,8 +2809,7 @@ public class BrokerImpl
if (load != null) { if (load != null) {
int mode = (dfgOnly) ? _store.FORCE_LOAD_DFG int mode = (dfgOnly) ? _store.FORCE_LOAD_DFG
: _store.FORCE_LOAD_ALL; : _store.FORCE_LOAD_ALL;
failed = _store.loadAll(load, null, mode, _fc.newFetchState(), failed = _store.loadAll(load, null, mode, _fc, null);
null);
if (failed != null && !failed.isEmpty()) if (failed != null && !failed.isEmpty())
exceps = add(exceps, newObjectNotFoundException(failed)); exceps = add(exceps, newObjectNotFoundException(failed));
} }
@ -3196,7 +3192,7 @@ public class BrokerImpl
Collection failed = null; Collection failed = null;
if (load != null) { if (load != null) {
failed = _store.loadAll(load, null, _store.FORCE_LOAD_NONE, failed = _store.loadAll(load, null, _store.FORCE_LOAD_NONE,
_fc.newFetchState(), null); _fc, null);
if (failed != null && !failed.isEmpty()) if (failed != null && !failed.isEmpty())
exceps = add(exceps, exceps = add(exceps,
newObjectNotFoundException(failed)); newObjectNotFoundException(failed));
@ -4087,7 +4083,7 @@ public class BrokerImpl
Object oid = ApplicationIds.create(pc, meta); Object oid = ApplicationIds.create(pc, meta);
if (oid == null) if (oid == null)
return false; return false;
return find(oid, _fc.newFetchState(), EXCLUDE_ALL, null, 0) != null; return find(oid, null, EXCLUDE_ALL, null, 0) != null;
} }
public OpenJPAStateManager getStateManager(Object obj) { public OpenJPAStateManager getStateManager(Object obj) {

View File

@ -198,10 +198,10 @@ public class DelegatingBroker
} }
} }
public Object[] findAll(Collection oids, FetchState fetchState, public Object[] findAll(Collection oids, FetchConfiguration fetch,
BitSet exclude, Object edata, int flags) { BitSet exclude, Object edata, int flags) {
try { try {
return _broker.findAll(oids, fetchState, exclude, edata, flags); return _broker.findAll(oids, fetch, exclude, edata, flags);
} catch (RuntimeException re) { } catch (RuntimeException re) {
throw translate(re); throw translate(re);
} }

View File

@ -229,9 +229,9 @@ public class DelegatingFetchConfiguration
} }
} }
public boolean hasFetchGroup(Set groups) { public boolean hasAnyFetchGroup(Set groups) {
try { try {
return _fetch.hasFetchGroup(groups); return _fetch.hasAnyFetchGroup(groups);
} catch (RuntimeException re) { } catch (RuntimeException re) {
throw translate(re); throw translate(re);
} }

View File

@ -114,8 +114,8 @@ public abstract class DelegatingStoreManager
} }
public Collection loadAll(Collection sms, PCState state, int load, public Collection loadAll(Collection sms, PCState state, int load,
FetchState fetchState, Object context) { FetchConfiguration fetch, Object context) {
return _store.loadAll(sms, state, load, fetchState, context); return _store.loadAll(sms, state, load, fetch, context);
} }
public void beforeStateChange(OpenJPAStateManager sm, PCState fromState, public void beforeStateChange(OpenJPAStateManager sm, PCState fromState,

View File

@ -223,7 +223,7 @@ public class DetachManager
FieldMetaData[] fmds = sm.getMetaData().getFields(); FieldMetaData[] fmds = sm.getMetaData().getFields();
for (int i = 0; i < fmds.length; i++) { for (int i = 0; i < fmds.length; i++) {
if (fmds[i].isPrimaryKey() || fmds[i].isInDefaultFetchGroup() if (fmds[i].isPrimaryKey() || fmds[i].isInDefaultFetchGroup()
|| fetch.hasFetchGroup(fmds[i].getFetchGroups()) || fetch.hasAnyFetchGroup(fmds[i].getFetchGroups())
|| fetch.hasField(fmds[i].getFullName())) || fetch.hasField(fmds[i].getFullName()))
idxs.set(i); idxs.set(i);
} }

View File

@ -136,9 +136,10 @@ public class DetachedStateManager
load.set(i); load.set(i);
} }
} }
FetchConfiguration fc = broker.getFetchConfiguration();
sm.loadFields(load, null, broker.getFetchConfiguration(). FetchState fetchState = fc.newFetchState();
getWriteLockLevel(), null, true); sm.loadFields(load, fetchState, fc.getWriteLockLevel(), null, true);
} }
sm.setVersion(_version); sm.setVersion(_version);

View File

@ -45,6 +45,7 @@ public interface FetchConfiguration
public static final String FETCH_GROUP_ALL = public static final String FETCH_GROUP_ALL =
"org.apache.openjpa.kernel.FetchConfiguration.FETCH_GROUP_ALL"; "org.apache.openjpa.kernel.FetchConfiguration.FETCH_GROUP_ALL";
public static final String FETCH_GROUP_DEFAULT = "default";
/** /**
* Return the context assiciated with this configuration; * Return the context assiciated with this configuration;
* may be null if it has not been set or this object has been serialized. * may be null if it has not been set or this object has been serialized.
@ -144,7 +145,7 @@ public interface FetchConfiguration
* *
* @since 4.1 * @since 4.1
*/ */
public boolean hasFetchGroup(Set groups); public boolean hasAnyFetchGroup(Set groups);
/** /**
* Adds <code>group</code> to the set of fetch group names to * Adds <code>group</code> to the set of fetch group names to

View File

@ -108,6 +108,7 @@ public class FetchConfigurationImpl
public void copy(FetchConfiguration fetch) { public void copy(FetchConfiguration fetch) {
setFetchBatchSize(fetch.getFetchBatchSize()); setFetchBatchSize(fetch.getFetchBatchSize());
setMaxFetchDepth(fetch.getMaxFetchDepth());
setQueryCache(fetch.getQueryCache()); setQueryCache(fetch.getQueryCache());
setFlushBeforeQueries(fetch.getFlushBeforeQueries()); setFlushBeforeQueries(fetch.getFlushBeforeQueries());
setLockTimeout(fetch.getLockTimeout()); setLockTimeout(fetch.getLockTimeout());
@ -172,11 +173,11 @@ public class FetchConfigurationImpl
public synchronized boolean hasFetchGroup(String group) { public synchronized boolean hasFetchGroup(String group) {
return _fetchGroups != null return _fetchGroups != null
&& ((group != null && _fetchGroups.contains(group)) && (_fetchGroups.contains(group)
|| _fetchGroups.contains(FETCH_GROUP_ALL)); || _fetchGroups.contains(FETCH_GROUP_ALL));
} }
public synchronized boolean hasFetchGroup(Set groups) { public synchronized boolean hasAnyFetchGroup(Set groups) {
if (_fetchGroups != null && groups != null) { if (_fetchGroups != null && groups != null) {
Iterator iter = groups.iterator(); Iterator iter = groups.iterator();
while (iter.hasNext()) { while (iter.hasNext()) {

View File

@ -1,68 +1,135 @@
/* /*
* Copyright 2006 The Apache Software Foundation. * Copyright 2006 The Apache Software Foundation.
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* 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
* http://www.apache.org/licenses/LICENSE-2.0 * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* Unless required by applicable law or agreed to in writing, software * See the License for the specific language governing permissions and
* distributed under the License is distributed on an "AS IS" BASIS, * limitations under the License.
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
* See the License for the specific language governing permissions and package org.apache.openjpa.kernel;
* limitations under the License.
*/ import java.io.Serializable;
package org.apache.openjpa.kernel; import java.util.List;
import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.FieldMetaData;
/** /**
* Defines the decision to include fields for selection or loading during * Defines the decision to include fields for selection or loading during
* a fetch operation. * a fetch operation.
* * A state is resulted by traversal of a relationship except the <em>root</em>
* @author <A HREF="mailto:pinaki.poddar@gmail.com>Pinaki Poddar</A> * state.
* @since 4.1 *
*/ * @author <A HREF="mailto:pinaki.poddar@gmail.com>Pinaki Poddar</A>
public interface FetchState { * @since 4.1
*/
/** public interface FetchState
* Returns the immutable fetch configuration this receiver is based on. extends Serializable, Cloneable {
*/
public FetchConfiguration getFetchConfiguration(); public static final int INFINITE_DEPTH = -1;
/** /**
* Affirms if the given field requires to be selected in the context * Returns the immutable fetch configuration this receiver is based on.
* of current fetch operation. */
* The response can be stateful as the same field argument would generate public FetchConfiguration getFetchConfiguration();
* different responses on different invocation based on the current
* state of this receiver if changeState flag is true. /**
* * Affirms if the given field requires to be fetched in the context
* @param fm field metadata. must not be null. * of current fetch operation.
* @param changeState true implies that the state of the receiver will *
* change due to invocation. * @param fm field metadata. must not be null.
*/ */
public boolean requiresSelect(FieldMetaData fm, boolean changeState); public boolean requiresFetch(FieldMetaData fm);
/** /**
* Affirms if the given field of the given instance requires to be loaded * Affirms if the given field of the given instance requires to be loaded
* in the context of current fetch operation. * in the context of current fetch operation.
* The response is stateful as the same arguments would generate different *
* responses on different invocation based on the current state of this * @param sm state manager being populated
* receiver. * @param fm field metadata
* */
* @param sm state manager being populated public boolean requiresLoad(OpenJPAStateManager sm, FieldMetaData fm);
* @param fm field metadata
*/ /**
public boolean requiresLoad(OpenJPAStateManager sm, FieldMetaData fm); * Traverse the given field to generate (possibly) a new state.
*
/** * @param fm
* Affirms if the given field is to be loaded as default. The field itself * @return a new state resulting out of traversal. If the given field is
* is aware of whether it belongs to the default fetch group. This method * not a relation then return itself.
* adds an extra constraint to verify that current configuration includes */
* default fetch group. public FetchState traverse (FieldMetaData fm);
*
* @param fm field metadata /**
*/ * Gets the available depth i.e. number of relations that can be traveresed
public boolean isDefault(FieldMetaData fm); * from this receiver.
} *
* @return a positive integer with positive infinity designated as
* <code>-1</code>.
*/
public int getAvailableFetchDepth ();
/**
* Gets the root state where this receiver is derived from.
* @return itself if the state is not derived from another state.
*
*/
public FetchState getRoot ();
/**
* Affirms if this receiver is the root state i.e. not derived as a result
* of traversing a relationship.
*
*/
public boolean isRoot ();
/**
* Gets the parent state.
* @return can be null for the root state.
*/
public FetchState getParent ();
/**
* Gets an ordered list of states from this receiver to its root.
*
* @return the order starts from this receiver and ends in the
* root. An empty list if this receiver is the root.
*/
public List getPath ();
/**
* Gets an ordered list of relation fields from this receiver to its root.
* These relations denote the path traversals from the root that resulted
* in the current state.
*
* @return the list starts from relation traversal of which resulted in this
* receiver and ends in the relation traversed from the root.
* An empty list, if this receiver itself is the root.
*/
public List getRelationPath ();
/**
* Gets the number of times the given field is traversed to arrive
* at this state.
*
* @param fm
* @return
*/
public int getCurrentRecursionDepth (FieldMetaData fm);
/**
* Gets the recursion depth of the given field.
*
* @param fm a relation field
* @return If the field has multiple fetch groups in the current
* configuration, then the recursion depth is maximum of all the recursion
* depths.
* The default recursion depth, if none is explictly specified, is 1.
* The infinite i.e. unlimited recursion depth is designated as
* <code>-1</code>
*/
public int getRecursionDepth (FieldMetaData fm);
}

View File

@ -1,205 +1,234 @@
/* /*
* Copyright 2006 The Apache Software Foundation. * Copyright 2006 The Apache Software Foundation.
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* 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
* http://www.apache.org/licenses/LICENSE-2.0 * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* Unless required by applicable law or agreed to in writing, software * See the License for the specific language governing permissions and
* distributed under the License is distributed on an "AS IS" BASIS, * limitations under the License.
* 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.kernel;
*
*/ import java.util.*;
package org.apache.openjpa.kernel;
import org.apache.openjpa.enhance.StateManager;
import java.io.Serializable; import org.apache.openjpa.meta.FetchGroup;
import java.util.HashMap; import org.apache.openjpa.meta.FieldMetaData;
import java.util.HashSet; import org.apache.openjpa.util.InternalException;
import java.util.Iterator;
import java.util.Map; /**
import java.util.Set; * Holds dynamic status of fetch operation. Decides whether a field
* requires to be selected/loaded under present condition.
import org.apache.openjpa.meta.ClassMetaData; *
import org.apache.openjpa.meta.FetchGroup; * @author <A HREF="mailto:pinaki.poddar@gmail.com>Pinaki Poddar</A>
import org.apache.openjpa.meta.FieldMetaData; * @nojavadoc
import org.apache.openjpa.meta.JavaTypes; */
public class FetchStateImpl implements FetchState {
/**
* Holds dynamic status of fetch operation. Decides whether a field private final FetchConfiguration _config;
* requires to be selected/loaded under present condition. private FetchState _parent;
* private FieldMetaData _relation;
* @author <A HREF="mailto:pinaki.poddar@gmail.com>Pinaki Poddar</A> private int _availableDepth;
* @nojavadoc
*/ /**
public class FetchStateImpl * Supply configuration.
implements FetchState, Serializable { *
* @param fc must not be null.
private final FetchConfiguration _config; */
public FetchStateImpl(FetchConfiguration fc) {
private Map _selectTraversals; _config = fc;
private Map _loadTraversals; _parent = null;
private Map _recursionDepths; _relation = null;
private Map _depths; _availableDepth = _config.getMaxFetchDepth();
private int _depth; }
private final Set _knownExcludes;
private static final int INFINITE_DEPTH = -1; public FetchConfiguration getFetchConfiguration() {
return _config;
/** }
* Supply configuration.
* public FetchState getParent () {
* @param fc must not be null. return _parent;
*/ }
public FetchStateImpl(FetchConfiguration fc) {
super(); public boolean isRoot () {
_config = fc; return _parent == null;
_knownExcludes = new HashSet(); }
_selectTraversals = new HashMap();
_loadTraversals = new HashMap(); public FetchState getRoot() {
_depths = new HashMap(); return (isRoot()) ? this : getParent().getRoot();
_recursionDepths = new HashMap(); }
}
public int getAvailableFetchDepth() {
public FetchConfiguration getFetchConfiguration() { return _availableDepth;
return _config; }
}
public List getPath () {
public boolean isDefault(FieldMetaData fm) { if (isRoot())
return _config.hasFetchGroup(FetchGroup.getDefaultGroupName()) return Collections.EMPTY_LIST;
&& fm.isInDefaultFetchGroup(); List result = new ArrayList();
} result.add (this);
return ((FetchStateImpl)_parent).trackPath (result);
public boolean requiresSelect(FieldMetaData fm, boolean changeState) { }
if (_knownExcludes.contains(fm))
return false; private List trackPath (List path) {
boolean selectable = isDefault(fm) if (isRoot())
|| _config.hasFetchGroup(fm.getFetchGroups()) return path;
|| _config.hasField(fm.getFullName()); path.add(this);
if (!selectable) return ((FetchStateImpl)_parent).trackPath(path);
_knownExcludes.add(fm); }
if (selectable && JavaTypes.maybePC(fm)) // relation field public List getRelationPath () {
{ if (isRoot())
if (canTraverse(fm)) { return Collections.EMPTY_LIST;
if (changeState) List result = new ArrayList();
traverse(fm); result.add (_relation);
} else return ((FetchStateImpl)_parent).trackRelationPath (result);
selectable = false; }
}
return selectable; private List trackRelationPath (List path) {
} if (isRoot())
return path;
public boolean requiresLoad(OpenJPAStateManager sm, FieldMetaData fm) { path.add(_relation);
boolean loadable = isDefault(fm) return ((FetchStateImpl)_parent).trackRelationPath(path);
|| _config.hasFetchGroup(fm.getFetchGroups()) }
|| _config.hasField(fm.getFullName());
if (!loadable)
_knownExcludes.add(fm); public int getCurrentRecursionDepth (FieldMetaData fm) {
// relation field if (isRoot())
if (loadable && JavaTypes.maybePC(fm)) { return 0;
int d = getLoadCount(fm); int rd = (_relation == fm) ? 1 : 0;
loadable = (d < (getTraversalCount(fm) - 1));
if (loadable) return rd + _parent.getCurrentRecursionDepth(fm);
_loadTraversals.put(fm, new Integer(d + 1)); }
}
return loadable; public boolean isDefault(FieldMetaData fm) {
} return (_config.hasFetchGroup(FetchConfiguration.FETCH_GROUP_DEFAULT)
&& fm.isInDefaultFetchGroup())
/** || _config.hasFetchGroup(FetchConfiguration.FETCH_GROUP_ALL);
* Get the recusion depth for the given field. }
*
* @param fm is the field to look for public boolean requiresFetch(FieldMetaData fm) {
* @return 0 if the field does not appear in the given map. boolean selectable = isDefault(fm)
*/ || _config.hasAnyFetchGroup(fm.getFetchGroups())
protected int getRecursionDepth(FieldMetaData fm) { || _config.hasField(fm.getFullName());
if (_recursionDepths.containsKey(fm)) { if (selectable && isRelation(fm)) {
return ((Integer) _recursionDepths.get(fm)).intValue(); int rd = getRecursionDepth(fm);
} int crd = getCurrentRecursionDepth(fm);
return initalizeRecusrionDepth(fm); selectable = (_availableDepth==INFINITE_DEPTH || _availableDepth>0)
} && ( rd == INFINITE_DEPTH || crd <rd);
}
/** return selectable;
* Sets the recursion depth for the given field as the maximum recusion }
* depth among the groups common to this field and configured fetch groups.
* public boolean requiresLoad(OpenJPAStateManager sm, FieldMetaData fm) {
* @param fm if (sm!=null && sm.getLoaded().get(fm.getIndex()))
* @return maximum recursion depth across common fetch groups. -1 is treated return false;
* as positive infinity. boolean loadable = isDefault(fm)
*/ || _config.hasAnyFetchGroup(fm.getFetchGroups())
protected int initalizeRecusrionDepth(FieldMetaData fm) { || _config.hasField(fm.getFullName());
Set commonFGNs = new HashSet(); if (loadable && isRelation(fm)) {
commonFGNs.addAll(_config.getFetchGroups()); int rd = getRecursionDepth(fm);
commonFGNs.retainAll(fm.getFetchGroups()); int crd = getCurrentRecursionDepth(fm);
loadable = (_availableDepth==INFINITE_DEPTH || _availableDepth>0)
int dMax = (commonFGNs.isEmpty()) ? FetchGroup.DEFAULT_RECURSION_DEPTH && (rd == INFINITE_DEPTH || crd<rd);
: 0; }
Iterator i = commonFGNs.iterator(); return loadable;
while (i.hasNext()) { }
FetchGroup fg = fm.getDeclaringMetaData()
.getFetchGroup(i.next().toString(), false);
int d = fg.getDepthFor(fm); /**
if (d == INFINITE_DEPTH) { * Sets the recursion depth for the given field as the maximum recusion
dMax = INFINITE_DEPTH; * depth among the groups common to this field and configured fetch groups.
break; *
} * @param fm
dMax = Math.max(d, dMax); * @return maximum recursion depth across common fetch groups. -1 is treated
} * as positive infinity.
_recursionDepths.put(fm, new Integer(dMax)); */
public int getRecursionDepth(FieldMetaData fm) {
return dMax; Set commonFGNs = new HashSet();
} commonFGNs.addAll(_config.getFetchGroups());
commonFGNs.retainAll(fm.getFetchGroups());
boolean canTraverse(FieldMetaData fm) { int dMax =
int maxDepth = _config.getMaxFetchDepth(); (commonFGNs.isEmpty()) ? FetchGroup.DEFAULT_RECURSION_DEPTH : 0;
if (maxDepth != INFINITE_DEPTH && _depth > maxDepth) Iterator i = commonFGNs.iterator();
return false; while (i.hasNext()) {
int sourceDepth = getDepth(fm.getDeclaringMetaData()); FetchGroup fg = fm.getDeclaringMetaData()
int traversalCount = getTraversalCount(fm); .getFetchGroup(i.next().toString());
int recursionDepth = getRecursionDepth(fm); int d = fg.getDepthFor(fm);
int newtargetDepth = sourceDepth + traversalCount + 1; if (d == INFINITE_DEPTH) {
boolean isRecursive = fm.getDeclaringMetaData() == dMax = INFINITE_DEPTH;
fm.getDeclaredTypeMetaData(); break;
boolean traversable = (maxDepth == INFINITE_DEPTH) }
|| (recursionDepth == INFINITE_DEPTH); dMax = Math.max(d, dMax);
if (isRecursive) }
traversable = traversable || (traversalCount < recursionDepth); int maxDepth = _config.getMaxFetchDepth();
else if (maxDepth != INFINITE_DEPTH)
traversable = traversable || (newtargetDepth <= maxDepth); if (dMax != INFINITE_DEPTH)
dMax = Math.min (maxDepth, dMax);
return traversable; else
} dMax = maxDepth;
void traverse(FieldMetaData fm) { return dMax;
int sourceDepth = getDepth(fm.getDeclaringMetaData()); }
int traversalCount = getTraversalCount(fm);
boolean isRecursive = fm.getDeclaringMetaData() ==
fm.getDeclaredTypeMetaData(); public FetchState traverse(FieldMetaData fm) {
if (!isRecursive) { if (isRelation(fm)) {
int newDepth = sourceDepth + traversalCount; try
_depths.put(fm.getDeclaredTypeMetaData(), new Integer(newDepth)); {
_depth = Math.max(_depth, newDepth); FetchStateImpl clone = (FetchStateImpl)clone();
} clone._parent = this;
_selectTraversals.put(fm, new Integer(traversalCount + 1)); clone._relation = fm;
} clone._availableDepth = reduce(_availableDepth);
return clone;
int getTraversalCount(FieldMetaData fm) { }
Integer n = (Integer) _selectTraversals.get(fm); catch (CloneNotSupportedException e)
return (n == null) ? 0 : n.intValue(); {
} // ignore
}
int getLoadCount(FieldMetaData fm) { }
Integer n = (Integer) _loadTraversals.get(fm); return this;
return (n == null) ? 0 : n.intValue(); }
}
int getDepth(ClassMetaData cm) { int reduce (int d) {
if (_depths.containsKey(cm)) if (d==0)
return ((Integer) _depths.get(cm)).intValue(); return 0;//throw new InternalException(this.toString());
return 0; if (d==INFINITE_DEPTH)
} return INFINITE_DEPTH;
}
return d-1;
}
protected boolean isRelation (FieldMetaData fm) {
return fm != null &&
(fm.isDeclaredTypePC()
|| (fm.getElement() != null && fm.getElement().isTypePC())
|| (fm.getKey() != null && fm.getKey().isTypePC())
|| (fm.getValue() != null && fm.getValue().isTypePC()));
}
public String toString () {
return System.identityHashCode(this) + "("+_availableDepth+"): "
+ printPath();
}
private String printPath ()
{
List path = getRelationPath();
if (path.isEmpty())
return "";
StringBuffer tmp = new StringBuffer();
Iterator i = path.iterator();
tmp.append(((FieldMetaData)i.next()).getName());
for (;i.hasNext();)
tmp.append(".").append(((FieldMetaData)i.next()).getName());
return tmp.toString();
}
}

View File

@ -102,8 +102,7 @@ class PNonTransState
if (context.getDirty().length() > 0) if (context.getDirty().length() > 0)
context.saveFields(true); context.saveFields(true);
context.clearFields(); context.clearFields();
context.load(context.getBroker().getFetchConfiguration(). context.load(null, context.LOAD_FGS, null, null, true);
newFetchState(), context.LOAD_FGS, null, null, true);
} }
return PDIRTY; return PDIRTY;
} }

View File

@ -18,14 +18,7 @@ package org.apache.openjpa.kernel;
import java.io.IOException; import java.io.IOException;
import java.io.ObjectOutput; import java.io.ObjectOutput;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.*;
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.TimeZone;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfiguration;
@ -325,6 +318,8 @@ public class StateManagerImpl
if (!forWrite && (!isPersistent() || isNew() || isDeleted())) if (!forWrite && (!isPersistent() || isNew() || isDeleted()))
return false; return false;
if (fetchState==null)
fetchState = _broker.getFetchConfiguration().newFetchState();
// if any fields being loaded, do state transitions for read // if any fields being loaded, do state transitions for read
BitSet fields = getUnloadedInternal(fetchState, loadMode, exclude); BitSet fields = getUnloadedInternal(fetchState, loadMode, exclude);
boolean active = _broker.isActive(); boolean active = _broker.isActive();
@ -2760,9 +2755,9 @@ public class StateManagerImpl
protected void loadField(int field, int lockLevel, boolean forWrite, protected void loadField(int field, int lockLevel, boolean forWrite,
boolean fgs) { boolean fgs) {
loadField(field, _broker.getFetchConfiguration().newFetchState(), FetchConfiguration fc = _broker.getFetchConfiguration();
lockLevel, forWrite, fgs); loadField(field, fc.newFetchState(),lockLevel, forWrite, fgs);
} }
/** /**
* Load the given field's fetch group; the field itself may already be * Load the given field's fetch group; the field itself may already be
@ -2799,7 +2794,7 @@ public class StateManagerImpl
// call this method even if there are no unloaded fields; loadFields // call this method even if there are no unloaded fields; loadFields
// takes care of things like loading version info and setting PC // takes care of things like loading version info and setting PC
// flags // flags
loadFields(fields, null, lockLevel, null, forWrite); loadFields(fields, fetchState, lockLevel, null, forWrite);
} }
/** /**
@ -2869,15 +2864,12 @@ public class StateManagerImpl
// is this field in the dfg? // is this field in the dfg?
FieldMetaData[] fmds = _meta.getDefaultFetchGroupFields(); FieldMetaData[] fmds = _meta.getDefaultFetchGroupFields();
if (fmds.length > 0 && field != -1
&& !requiredByDefault(_meta.getField(field), fetchState))
return;
// see if the dfg is fully loaded // see if any fetch group with postLoad=true is fully loaded
boolean isLoaded = true; boolean isLoaded = true;
for (int i = 0; isLoaded && i < fmds.length; i++) for (int i = 0; isLoaded && i < fmds.length; i++)
if (!_loaded.get(fmds[i].getIndex()) if (!_loaded.get(fmds[i].getIndex())
&& requiredByDefault(fmds[i], fetchState)) && requiresPostLoadCallabck(fmds[i], fetchState))
isLoaded = false; isLoaded = false;
if (isLoaded) { if (isLoaded) {
_flags |= FLAG_DFG; _flags |= FLAG_DFG;
@ -2885,15 +2877,18 @@ public class StateManagerImpl
} }
} }
private boolean requiredByDefault(FieldMetaData fm, FetchState fetchState) { private boolean requiresPostLoadCallabck(FieldMetaData fm, FetchState fetchState) {
if (fm == null) if (fm == null)
return false; return false;
if (fetchState == null) Set fetchGroups = fm.getFetchGroups();
return fm.isInDefaultFetchGroup() for (Iterator i = fetchGroups.iterator(); i.hasNext();)
&& _broker.getFetchConfiguration().hasFetchGroup {
(FetchGroup.getDefaultGroupName()); String fg = i.next().toString();
else if (_broker.getFetchConfiguration().hasFetchGroup(fg)
return fetchState.isDefault(fm); && fm.getDeclaringMetaData().getFetchGroup(fg).isPostLoad())
return true;
}
return false;
} }
/** /**

View File

@ -143,7 +143,7 @@ public interface StoreContext {
* *
* @see #find(Object,FetchState,BitSet,Object,int) * @see #find(Object,FetchState,BitSet,Object,int)
*/ */
public Object[] findAll(Collection oids, FetchState fetchState, public Object[] findAll(Collection oids, FetchConfiguration fetch,
BitSet exclude, Object edata, int flags); BitSet exclude, Object edata, int flags);
/** /**

View File

@ -210,7 +210,7 @@ public interface StoreManager
* @see org.apache.openjpa.util.ImplHelper#loadAll * @see org.apache.openjpa.util.ImplHelper#loadAll
*/ */
public Collection loadAll(Collection sms, PCState state, int load, public Collection loadAll(Collection sms, PCState state, int load,
FetchState fetchState, Object edata); FetchConfiguration fetch, Object edata);
/** /**
* Notification that the given state manager is about to change its * Notification that the given state manager is about to change its

View File

@ -130,7 +130,7 @@ class VersionAttachStrategy
break; break;
case DETACH_FGS: case DETACH_FGS:
if (fmds[i].isInDefaultFetchGroup() if (fmds[i].isInDefaultFetchGroup()
|| fetch.hasFetchGroup(fmds[i].getFetchGroups()) || fetch.hasAnyFetchGroup(fmds[i].getFetchGroups())
|| fetch.hasField(fmds[i].getFullName())) || fetch.hasField(fmds[i].getFullName()))
attachField(manager, toAttach, sm, fmds[i], true); attachField(manager, toAttach, sm, fmds[i], true);
break; break;

View File

@ -1922,10 +1922,12 @@ public class ClassMetaData
* the same name. * the same name.
*/ */
public synchronized FetchGroup addFetchGroup(String name) { public synchronized FetchGroup addFetchGroup(String name) {
if (name == null || name.trim().length()==0)
throw new MetaDataException(_loc.get("empty-fg-name", this));
FetchGroup fg = (FetchGroup) _fgs.get(name); FetchGroup fg = (FetchGroup) _fgs.get(name);
if (fg == null) { if (fg == null) {
fg = newFetchGroup(name); fg = new FetchGroup(this, name);
_fgs.put(name, fg); _fgs.put(name, fg);
} }
return fg; return fg;
@ -1933,33 +1935,19 @@ public class ClassMetaData
/** /**
* Gets a named fecth group. If not available in this receiver then looks * Gets a named fecth group. If not available in this receiver then looks
* up the inheritence hierarchy. Creates if it does not exist and * up the inheritence hierarchy.
* <code>mustBe</code> is false.
* *
* @param name name of a fetch group. * @param name name of a fetch group.
* @param mustBe if true then the named group must exist in this receiver * @return an existing fecth group of the given name if known to this
* or any of its persistent super classes. * receiver or any of its superclasses. Otherwise null.
* @return an existing or newly created fecth group of the given name.
*/ */
public synchronized FetchGroup getFetchGroup(String name, boolean mustBe) { public synchronized FetchGroup getFetchGroup(String name) {
FetchGroup fg = (FetchGroup) _fgs.get(name); FetchGroup fg = (FetchGroup) _fgs.get(name);
if (fg == null) { if (fg == null) {
ClassMetaData scm = getPCSuperclassMetaData(); ClassMetaData scm = getPCSuperclassMetaData();
if (scm != null) if (scm != null)
fg = scm.getFetchGroup(name, false); fg = scm.getFetchGroup(name);
} }
if (fg == null)
if (mustBe)
return null;
else
fg = addFetchGroup(name);
return fg;
}
protected FetchGroup newFetchGroup(String name) {
FetchGroup fg = new FetchGroup(this, name);
return fg; return fg;
} }

View File

@ -1,205 +1,173 @@
/* /*
* Copyright 2006 The Apache Software Foundation. * Copyright 2006 The Apache Software Foundation.
* * Licensed under the Apache License, Version 2.0 (the "License");
* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.
* you may not use this file except in compliance with the License. * You may obtain a copy of the License at
* 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
* http://www.apache.org/licenses/LICENSE-2.0 * distributed under the License is distributed on an "AS IS" BASIS,
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* Unless required by applicable law or agreed to in writing, software * See the License for the specific language governing permissions and
* distributed under the License is distributed on an "AS IS" BASIS, * limitations under the License.
* 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.meta;
*
*/ import java.io.File;
package org.apache.openjpa.meta; import java.util.ArrayList;
import java.util.HashMap;
import java.io.File; import java.util.Iterator;
import java.util.ArrayList; import java.util.List;
import java.util.HashMap; import java.util.Map;
import java.util.Iterator;
import java.util.List; import org.apache.commons.lang.StringUtils;
import java.util.Map; import org.apache.openjpa.lib.meta.SourceTracker;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.commons.lang.StringUtils; import org.apache.openjpa.util.UserException;
import org.apache.openjpa.lib.meta.SourceTracker;
import org.apache.openjpa.lib.util.Localizer; /**
import org.apache.openjpa.util.MetaDataException; * Captures fetch group metadata.
*/
/** public class FetchGroup implements SourceTracker {
* Captures fetch group metadata.
*/ private final String _name;
public class FetchGroup private final ClassMetaData _declaringClass;
implements SourceTracker { private List _includes;
private Map _depths;
private final String _name; private boolean _postLoad;
private final ClassMetaData _declaringClass; public static final int DEFAULT_RECURSION_DEPTH = 1;
private List _includes; private static final Localizer _loc =
private Map _depths; Localizer.forPackage(FetchGroup.class);
public static final int DEFAULT_RECURSION_DEPTH = 1; /**
private static String DEFAULT_GROUP_NAME = "default"; * Supply immutable name.
*
private static final Localizer _loc = Localizer.forPackage * @param must not by null or empty.
(FetchGroup.class); */
FetchGroup(ClassMetaData cm, String name) {
/** super();
* Supply immutable name. if (StringUtils.isEmpty(name))
* throw new UserException(_loc.get("invalid-fg-name", cm, name));
* @param name must not by null or empty. _name = name;
*/ _declaringClass = cm;
FetchGroup(ClassMetaData cm, String name) { }
super();
public String getName() {
if (cm == null) return _name;
throw new MetaDataException(_loc.get("null-class-fg", name)); }
if (StringUtils.isEmpty(name))
throw new MetaDataException(_loc.get("invalid-fg-name", cm, /**
name)); * Includes given fetch group within this receiver.
*
_name = name; * @param fg must not be null or this receiver itself or must not include
_declaringClass = cm; * this receiver.
} */
public void addInclude(FetchGroup fg) {
public String getName() { if (fg == this)
return _name; throw new UserException(_loc.get("self-include-fg", this));
} if (fg == null)
throw new UserException(_loc.get("null-include-fg", this));
/** if (fg.includes(this, true))
* Includes given fetch group within this receiver. throw new UserException(_loc.get("cyclic-fg", this, fg));
* if (_includes == null)
* @param fg must not be null or this receiver itself or must not include _includes = new ArrayList();
* this receiver. _includes.add(fg);
*/ }
public void addInclude(FetchGroup fg) {
if (fg == this) /**
throw new MetaDataException(_loc.get("self-include-fg", this)); * Affirms if given fetch group is included by this receiver.
if (fg == null) *
throw new MetaDataException(_loc.get("null-include-fg", this)); * @param fg
if (fg.includes(this, true)) * @param recurse if true then recursively checks within the included
throw new MetaDataException(_loc.get("cyclic-fg", this, fg)); * fecth groups. Otherwise just checks within direct includes.
* @return
if (_includes == null) */
_includes = new ArrayList(); public boolean includes(FetchGroup fg, boolean recurse) {
_includes.add(fg); if (_includes == null)
} return false;
if (_includes.contains(fg))
/** return true;
* Affirms if given fetch group is included by this receiver. if (recurse)
* for (Iterator i = _includes.iterator(); i.hasNext();)
* @param fg if (((FetchGroup) i.next()).includes(fg, true))
* @param recurse if true then recursively checks within the included return true;
* fecth groups. Otherwise just checks within direct includes. return false;
*/ }
public boolean includes(FetchGroup fg, boolean recurse) {
if (_includes == null) /**
return false; * Sets recursion depth for a field.
if (_includes.contains(fg)) *
return true; * @param fm
* @param depth
if (recurse) */
for (Iterator i = _includes.iterator(); i.hasNext();) public void setDepthFor(FieldMetaData fm, int depth) {
if (((FetchGroup) i.next()).includes(fg, true)) if (depth < -1)
return true; throw new UserException(_loc.get("invalid-fetch-depth",
_name, fm, new Integer(depth)));
return false; if (_depths == null)
} _depths = new HashMap();
_depths.put(fm, new Integer(depth));
/** }
* Sets recursion depth for a field.
* /**
* @param fm * Gets recusrion depth for the given field.
* @param depth *
*/ * @param fm
public void setDepthFor(FieldMetaData fm, int depth) { * @return defaults to 1.
if (depth < -1) */
throw new MetaDataException(_loc.get("invalid-fetch-depth", public int getDepthFor(FieldMetaData fm) {
_name, fm, new Integer(depth))); if (_depths == null || !_depths.containsKey(fm))
return DEFAULT_RECURSION_DEPTH;
if (_depths == null) return ((Integer) _depths.get(fm)).intValue();
_depths = new HashMap(); }
_depths.put(fm, new Integer(depth));
} public boolean isPostLoad () {
return _postLoad;
/** }
* Gets recusrion depth for the given field.
* public void setPostLoad (boolean flag) {
* @param fm _postLoad = flag;
* @return defaults to 1. }
*/
public int getDepthFor(FieldMetaData fm) { /**
if (_depths == null || !_depths.containsKey(fm)) * Affirms equality if the other has the same name.
return DEFAULT_RECURSION_DEPTH; */
public boolean equals(Object other) {
return ((Integer) _depths.get(fm)).intValue(); if (other instanceof FetchGroup) {
} FetchGroup that = (FetchGroup) other;
return _name.equals(that._name)
/** && _declaringClass.equals(that._declaringClass);
* Set the name for default group. }
* It is expected to be set only once by a compliant implementation. return false;
* If multiple attempts are made to set the <em>default</em> group name, }
* then an attempt will succeed only for the first time or if the given
* name matches with the current name. public int hashCode() {
* return _name.hashCode() + _declaringClass.hashCode();
* @param name of the default fetch group }
*/
public static void setDefaultGroupName(String name) { public String toString() {
//###JDO2 -- better mechanics required to set default group name return _name;
DEFAULT_GROUP_NAME = name; }
}
/////////////////
/** // SourceTracker
* Get the name in which <em>default</em> fetch group is known. /////////////////
* public File getSourceFile() {
* @return name of the default group. Can be null, if not set. return _declaringClass.getSourceFile();
*/ }
public static final String getDefaultGroupName() {
return DEFAULT_GROUP_NAME; public Object getSourceScope() {
} return _declaringClass;
}
/**
* Affirms equality if the other has the same name. public int getSourceType() {
*/ return _declaringClass.getSourceType();
public boolean equals(Object other) { }
if (other instanceof FetchGroup) {
FetchGroup that = (FetchGroup) other; public String getResourceName() {
return _name.equals(that._name) return _declaringClass.getResourceName();
&& _declaringClass.equals(that._declaringClass); }
} }
return false;
}
public int hashCode() {
return _name.hashCode() + _declaringClass.hashCode();
}
public String toString() {
return _name;
}
/////////////////
// SourceTracker
/////////////////
public File getSourceFile() {
return _declaringClass.getSourceFile();
}
public Object getSourceScope() {
return _declaringClass;
}
public int getSourceType() {
return _declaringClass.getSourceType();
}
public String getResourceName() {
return _declaringClass.getResourceName ();
}
}

View File

@ -39,6 +39,7 @@ import org.apache.commons.collections.comparators.ComparatorChain;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.kernel.StoreContext; import org.apache.openjpa.kernel.StoreContext;
import org.apache.openjpa.lib.conf.Configurations; import org.apache.openjpa.lib.conf.Configurations;
@ -849,13 +850,13 @@ public class FieldMetaData
*/ */
public void addFetchGroup(String fg) { public void addFetchGroup(String fg) {
if (StringUtils.isEmpty(fg)) if (StringUtils.isEmpty(fg))
return; throw new MetaDataException(_loc.get("bad-fg", fg));
if (getDeclaringMetaData().getFetchGroup(fg, false) == null) if (getDeclaringMetaData().getFetchGroup(fg) == null)
throw new MetaDataException(_loc.get("unknown-fg", fg)); throw new MetaDataException(_loc.get("unknown-fg", fg));
if (_fgs == null) if (_fgs == null)
_fgs = new HashSet(); _fgs = new HashSet();
_fgs.add(fg); _fgs.add(fg);
if (fg.equals(FetchGroup.getDefaultGroupName())) if (fg.equals(FetchConfiguration.FETCH_GROUP_DEFAULT))
setInDefaultFetchGroup(true); setInDefaultFetchGroup(true);
} }
@ -863,7 +864,7 @@ public class FieldMetaData
if (_fgs == null) if (_fgs == null)
return; return;
_fgs.remove(fg); _fgs.remove(fg);
if (fg != null && fg.equals(FetchGroup.getDefaultGroupName())) if (FetchConfiguration.FETCH_GROUP_DEFAULT.equals(fg))
setInDefaultFetchGroup(false); setInDefaultFetchGroup(false);
} }

View File

@ -23,6 +23,7 @@ import java.util.Iterator;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.openjpa.enhance.PersistenceCapable; import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.FetchState; import org.apache.openjpa.kernel.FetchState;
import org.apache.openjpa.kernel.LockManager; import org.apache.openjpa.kernel.LockManager;
import org.apache.openjpa.kernel.OpenJPAStateManager; import org.apache.openjpa.kernel.OpenJPAStateManager;
@ -90,18 +91,18 @@ public class ImplHelper {
* @since 4.0 * @since 4.0
*/ */
public static Collection loadAll(Collection sms, StoreManager store, public static Collection loadAll(Collection sms, StoreManager store,
PCState state, int load, FetchState fetchState, Object context) { PCState state, int load, FetchConfiguration fetch, Object context) {
Collection failed = null; Collection failed = null;
OpenJPAStateManager sm; OpenJPAStateManager sm;
LockManager lm; LockManager lm;
for (Iterator itr = sms.iterator(); itr.hasNext();) { for (Iterator itr = sms.iterator(); itr.hasNext();) {
sm = (OpenJPAStateManager) itr.next(); sm = (OpenJPAStateManager) itr.next();
FetchState fetchState = fetch.newFetchState();
if (sm.getManagedInstance() == null) { if (sm.getManagedInstance() == null) {
if (!store.initialize(sm, state, fetchState, context)) if (!store.initialize(sm, state, fetchState, context))
failed = addFailedId(sm, failed); failed = addFailedId(sm, failed);
} else if (load != StoreManager.FORCE_LOAD_NONE } else if (load != StoreManager.FORCE_LOAD_NONE
|| sm.getPCState() == PCState.HOLLOW) { || sm.getPCState() == PCState.HOLLOW) {
lm = sm.getContext().getLockManager(); lm = sm.getContext().getLockManager();
if (!store.load(sm, sm.getUnloaded(fetchState), if (!store.load(sm, sm.getUnloaded(fetchState),
fetchState, lm.getLockLevel(sm), context)) fetchState, lm.getLockLevel(sm), context))