/* | |
* 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.kernel; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.NoSuchElementException; | |
import org.apache.commons.collections.Predicate; | |
import org.apache.commons.collections.iterators.FilterIterator; | |
import org.apache.commons.collections.iterators.IteratorChain; | |
import org.apache.openjpa.lib.rop.ResultObjectProvider; | |
import org.apache.openjpa.lib.rop.ResultObjectProviderIterator; | |
import org.apache.openjpa.lib.util.Closeable; | |
import org.apache.openjpa.lib.util.ReferenceHashSet; | |
import java.util.concurrent.locks.ReentrantLock; | |
import org.apache.openjpa.meta.ClassMetaData; | |
import org.apache.openjpa.meta.MetaDataRepository; | |
import org.apache.openjpa.util.GeneralException; | |
import org.apache.openjpa.util.ImplHelper; | |
import org.apache.openjpa.util.OpenJPAException; | |
/** | |
* Representation of all members of a persistent class. | |
* | |
* @author Abe White | |
* @author Patrick Linskey | |
* @nojavadoc | |
*/ | |
public class ExtentImpl | |
implements Extent { | |
private static final ClassMetaData[] EMPTY_METAS = new ClassMetaData[0]; | |
private final Broker _broker; | |
private final Class _type; | |
private final boolean _subs; | |
private final FetchConfiguration _fc; | |
private final ReentrantLock _lock; | |
private boolean _ignore = false; | |
// set of open iterators | |
private ReferenceHashSet _openItrs = null; | |
/** | |
* Constructor. | |
* | |
* @param broker the owning broker | |
* @param type the candidate class | |
* @param subs whether subclasses are included in the extent | |
*/ | |
ExtentImpl(Broker broker, Class type, boolean subs, | |
FetchConfiguration fetch) { | |
_broker = broker; | |
_type = type; | |
_subs = subs; | |
if (fetch != null) | |
_fc = fetch; | |
else | |
_fc = (FetchConfiguration) broker.getFetchConfiguration().clone(); | |
_ignore = broker.getIgnoreChanges(); | |
if (broker.getMultithreaded()) | |
_lock = new ReentrantLock(); | |
else | |
_lock = null; | |
} | |
public FetchConfiguration getFetchConfiguration() { | |
return _fc; | |
} | |
public boolean getIgnoreChanges() { | |
return _ignore; | |
} | |
public void setIgnoreChanges(boolean ignoreChanges) { | |
_broker.assertOpen(); | |
_ignore = ignoreChanges; | |
} | |
public List list() { | |
List list = new ArrayList(); | |
Iterator itr = iterator(); | |
try { | |
while (itr.hasNext()) | |
list.add(itr.next()); | |
return list; | |
} finally { | |
ImplHelper.close(itr); | |
} | |
} | |
public Iterator iterator() { | |
_broker.assertNontransactionalRead(); | |
CloseableIterator citr = null; | |
try { | |
// create an iterator chain; add pnew objects if transactional | |
CloseableIteratorChain chain = new CloseableIteratorChain(); | |
boolean trans = !_ignore && _broker.isActive(); | |
if (trans) | |
chain.addIterator(new FilterNewIterator()); | |
// add database iterators for each implementing class | |
MetaDataRepository repos = _broker.getConfiguration(). | |
getMetaDataRepositoryInstance(); | |
ClassMetaData meta = repos.getMetaData(_type, | |
_broker.getClassLoader(), false); | |
ClassMetaData[] metas; | |
if (meta != null && (!_subs || !meta.isManagedInterface()) | |
&& (meta.isMapped() || (_subs | |
&& meta.getMappedPCSubclassMetaDatas().length > 0))) | |
metas = new ClassMetaData[]{ meta }; | |
else if (_subs && (meta == null || meta.isManagedInterface())) | |
metas = repos.getImplementorMetaDatas(_type, | |
_broker.getClassLoader(), false); | |
else | |
metas = EMPTY_METAS; | |
ResultObjectProvider rop; | |
for (int i = 0; i < metas.length; i++) { | |
rop = _broker.getStoreManager().executeExtent(metas[i], | |
_subs, _fc); | |
if (rop != null) | |
chain.addIterator(new ResultObjectProviderIterator(rop)); | |
} | |
// filter deleted objects if transactional | |
if (trans) | |
citr = new FilterDeletedIterator(chain); | |
else | |
citr = chain; | |
citr.setRemoveOnClose(this); | |
} catch (OpenJPAException ke) { | |
throw ke; | |
} catch (RuntimeException re) { | |
throw new GeneralException(re); | |
} | |
lock(); | |
try { | |
if (_openItrs == null) | |
_openItrs = new ReferenceHashSet(ReferenceHashSet.WEAK); | |
_openItrs.add(citr); | |
} finally { | |
unlock(); | |
} | |
return citr; | |
} | |
public Broker getBroker() { | |
return _broker; | |
} | |
public Class getElementType() { | |
return _type; | |
} | |
public boolean hasSubclasses() { | |
return _subs; | |
} | |
public void closeAll() { | |
if (_openItrs == null) | |
return; | |
lock(); | |
try { | |
CloseableIterator citr; | |
for (Iterator itr = _openItrs.iterator(); itr.hasNext();) { | |
citr = (CloseableIterator) itr.next(); | |
citr.setRemoveOnClose(null); | |
try { | |
citr.close(); | |
} catch (Exception e) { | |
} | |
} | |
_openItrs.clear(); | |
} catch (OpenJPAException ke) { | |
throw ke; | |
} catch (RuntimeException re) { | |
throw new GeneralException(re); | |
} finally { | |
unlock(); | |
} | |
} | |
public void lock() { | |
if (_lock != null) | |
_lock.lock(); | |
} | |
public void unlock() { | |
if (_lock != null) | |
_lock.unlock(); | |
} | |
/** | |
* Closeable iterator. | |
*/ | |
private static interface CloseableIterator | |
extends Closeable, Iterator { | |
/** | |
* Set the extent to remove self from on close. | |
*/ | |
public void setRemoveOnClose(ExtentImpl extent); | |
} | |
/** | |
* Closeable {@link IteratorChain}. | |
*/ | |
private static class CloseableIteratorChain | |
extends IteratorChain | |
implements CloseableIterator { | |
private ExtentImpl _extent = null; | |
private boolean _closed = false; | |
public boolean hasNext() { | |
return (_closed) ? false : super.hasNext(); | |
} | |
public Object next() { | |
if (_closed) | |
throw new NoSuchElementException(); | |
return super.next(); | |
} | |
public void remove() { | |
throw new UnsupportedOperationException(); | |
} | |
public void setRemoveOnClose(ExtentImpl extent) { | |
_extent = extent; | |
} | |
public void close() | |
throws Exception { | |
if (_extent != null && _extent._openItrs != null) { | |
_extent.lock(); | |
try { | |
_extent._openItrs.remove(this); | |
} finally { | |
_extent.unlock(); | |
} | |
} | |
_closed = true; | |
for (Iterator itr = getIterators().iterator(); itr.hasNext();) | |
((Closeable) itr.next()).close(); | |
} | |
} | |
/** | |
* {@link FilterIterator} that skips deleted objects. | |
*/ | |
private static class FilterDeletedIterator | |
extends FilterIterator | |
implements CloseableIterator, Predicate { | |
private ExtentImpl _extent = null; | |
private boolean _closed = false; | |
public FilterDeletedIterator(Iterator itr) { | |
super(itr); | |
setPredicate(this); | |
} | |
public boolean hasNext() { | |
return (_closed) ? false : super.hasNext(); | |
} | |
public Object next() { | |
if (_closed) | |
throw new NoSuchElementException(); | |
return super.next(); | |
} | |
public void remove() { | |
throw new UnsupportedOperationException(); | |
} | |
public void setRemoveOnClose(ExtentImpl extent) { | |
_extent = extent; | |
} | |
public void close() | |
throws Exception { | |
if (_extent != null && _extent._openItrs != null) { | |
_extent.lock(); | |
try { | |
_extent._openItrs.remove(this); | |
} finally { | |
_extent.unlock(); | |
} | |
} | |
_closed = true; | |
((Closeable) getIterator()).close(); | |
} | |
public boolean evaluate(Object o) { | |
return !_extent._broker.isDeleted(o); | |
} | |
} | |
/** | |
* Iterator over all new objects in this extent. This iterator is always | |
* wrapped, so it doesn't need to keep track of whether it's closed. | |
*/ | |
private class FilterNewIterator | |
extends FilterIterator | |
implements Closeable, Predicate { | |
public FilterNewIterator() { | |
super(_broker.getTransactionalObjects().iterator()); | |
setPredicate(this); | |
} | |
public void close() { | |
} | |
public boolean evaluate(Object o) { | |
if (!_broker.isNew(o)) | |
return false; | |
Class type = o.getClass(); | |
if (!_subs && type != _type) | |
return false; | |
if (_subs && !_type.isAssignableFrom(type)) | |
return false; | |
return true; | |
} | |
} | |
} |