com.gs.fw.common.mithra.list.AbstractTransactionalOperationBasedList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of reladomo Show documentation
Show all versions of reladomo Show documentation
Reladomo is an object-relational mapping framework.
/*
Copyright 2016 Goldman Sachs.
Licensed 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 com.gs.fw.common.mithra.list;
import com.gs.collections.impl.list.mutable.FastList;
import com.gs.fw.common.mithra.*;
import com.gs.fw.common.mithra.extractor.EmbeddedValueExtractor;
import com.gs.fw.common.mithra.attribute.*;
import com.gs.fw.common.mithra.finder.Operation;
import com.gs.fw.common.mithra.finder.MappedOperation;
import com.gs.collections.impl.set.mutable.UnifiedSet;
import com.gs.fw.common.mithra.finder.RelationshipMultiEqualityOperation;
import com.gs.fw.common.mithra.querycache.CachedQuery;
import com.gs.fw.common.mithra.transaction.MithraTransactionalResource;
import com.gs.fw.common.mithra.util.Time;
import java.sql.Timestamp;
import java.util.*;
import java.math.BigDecimal;
public class AbstractTransactionalOperationBasedList extends AbstractOperationBasedList implements MithraDelegatedTransactionalList
{
public static final AbstractTransactionalOperationBasedList DEFAULT = new AbstractTransactionalOperationBasedList(true);
private static final long BATCH_COMMAND_RETRY_SLEEP_TIME = 2000;
private static final int BATCH_COMMAND_DEFAULT_RETRY_COUNT = 5;
private DependentRelationshipRemoveHandler removeHandler = DefaultRemoveHandler.getInstance();
private DependentRelationshipAddHandler addHandler = DefaultAddHandler.getInstance();
public AbstractTransactionalOperationBasedList()
{
}
protected AbstractTransactionalOperationBasedList(boolean forDefaultUnused)
{
super(true);
}
@Override
protected AbstractTransactionalOperationBasedList newCopy()
{
return new AbstractTransactionalOperationBasedList();
}
@Override
protected AbstractTransactionalOperationBasedList copyIfDefault()
{
return (AbstractTransactionalOperationBasedList) super.copyIfDefault();
}
public MithraDelegatedTransactionalList zSetRemoveHandler(DelegatingList delegatingList, DependentRelationshipRemoveHandler removeHandler)
{
if (removeHandler != this.removeHandler)
{
AbstractTransactionalOperationBasedList result = copyIfDefault();
result.removeHandler = removeHandler;
return result;
}
return this;
}
public MithraDelegatedTransactionalList zSetAddHandler(DelegatingList delegatingList, DependentRelationshipAddHandler addHandler)
{
if (addHandler != this.addHandler)
{
AbstractTransactionalOperationBasedList result = copyIfDefault();
result.addHandler = addHandler;
return result;
}
return this;
}
protected boolean isOperationResolved(final DelegatingList delegatingList)
{
MithraTransaction threadTx = MithraManagerProvider.getMithraManager().getCurrentTransaction();
if (delegatingList.getOperation().getResultObjectPortal().getTxParticipationMode(threadTx).mustLockOnRead())
{
if (threadTx == null)
{
if (delegatingList.zGetCurrentTransaction() != null)
{
throw new MithraBusinessException("Lists are currently only supported in one transaction at a time!");
}
}
else if (!threadTx.equals(delegatingList.zGetCurrentTransaction()))
{
if (delegatingList.zGetCurrentTransaction() == null)
{
synchronized (delegatingList)
{
if (delegatingList.zGetCurrentTransaction() == null) // recheck under lock
{
this.clearResolved(delegatingList);
delegatingList.zSetCurrentTransaction(threadTx);
threadTx.enrollResource(new MithraTransactionalResource()
{
@Override
public void zHandleCommit()
{
commit(delegatingList);
}
@Override
public void zHandleRollback(MithraTransaction tx)
{
rollback(delegatingList);
}
});
}
}
}
else
{
throw new MithraBusinessException("Lists are currently only supported in one transaction at a time!");
}
}
}
return super.isOperationResolved(delegatingList);
}
public void commit(DelegatingList delegatingList)
{
delegatingList.zSetCurrentTransaction(null);
// this.clearResolved();
}
public void rollback(DelegatingList delegatingList)
{
delegatingList.zSetCurrentTransaction(null);
this.clearResolved(delegatingList);
}
public void insertAll(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be inserted!");
}
public void bulkInsertAll(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be bulk-inserted!");
}
public void cascadeInsertAll(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be inserted!");
}
public void cascadeInsertAllUntil(DelegatingList delegatingList, Timestamp exclusiveUntil)
{
throw new MithraBusinessException("An operation based list cannot be inserted!");
}
private boolean isComplexOperation(DelegatingList delegatingList)
{
Operation op = delegatingList.getOperation();
boolean oneByOne = (op instanceof MappedOperation);
if (!oneByOne)
{
UnifiedSet portals = new UnifiedSet(3);
op.addDependentPortalsToSet(portals);
MithraObjectPortal portal = op.getResultObjectPortal();
oneByOne = portals.size() > 1 || portal.getSuperClassPortals() != null || portal.getJoinedSubClassPortals() != null;
}
return oneByOne;
}
private void verifyNonDatedList(Operation op)
{
if (op.getResultObjectPortal().getClassMetaData().isDated())
{
throw new MithraBusinessException("Must not call deleteAll() on a Mithra list containing Dated objects. The terminate method will chain out an existing object.");
}
}
private void verifyNotInTransaction()
{
if (MithraManagerProvider.getMithraManager().isInTransaction())
{
throw new MithraTransactionException("deleteAllInBatches cannot be called from another transaction!");
}
}
private static void executeCommandInBatches(String commandName, int[] batchSize,TransactionalCommand command)
{
int affectedRows;
long sleepTime= BATCH_COMMAND_RETRY_SLEEP_TIME;
int retryCount = BATCH_COMMAND_DEFAULT_RETRY_COUNT;
do
{
try
{
do
{
affectedRows = (Integer) MithraManagerProvider.getMithraManager().executeTransactionalCommand(command, 0);
}
while(affectedRows >= batchSize[0]);
retryCount = 0;
}
catch (Throwable throwable)
{
retryCount = handleRetryException(commandName, throwable, retryCount);
try
{
Thread.sleep(sleepTime);
sleepTime *= 2;
}
catch(InterruptedException e)
{
//log something here
}
}
}
while(retryCount > 0);
}
private static int handleRetryException(String commandName, Throwable t, int retryCount)
{
--retryCount;
if(retryCount == 0)
{
throw new MithraBusinessException(commandName+" rolled back tx. All the retry attempts failed; will not retry.", t);
}
return retryCount;
}
public void deleteAll(DelegatingList delegatingList)
{
Operation op = delegatingList.getOperation();
verifyNonDatedList(op);
boolean oneByOne = (op instanceof MappedOperation);
if (!oneByOne)
{
UnifiedSet portals = new UnifiedSet(3);
op.addDependentPortalsToSet(portals);
MithraObjectPortal portal = op.getResultObjectPortal();
oneByOne = portals.size() > 1 || portal.getSuperClassPortals() != null || portal.getJoinedSubClassPortals() != null;
}
TransactionalCommand command = null;
if (oneByOne)
{
command = new DeleteAllOneByOneCommand(delegatingList);
}
else
{
command = new DeleteAllTransactionalCommand(delegatingList, this);
}
MithraManagerProvider.getMithraManager().executeTransactionalCommand(command);
}
public void deleteAllInBatches(DelegatingList delegatingList, int batchSize)
{
verifyNonDatedList(delegatingList.getOperation());
verifyNotInTransaction();
final int[] bSize = new int[1];
bSize[0] = batchSize;
TransactionalCommand command;
if (isComplexOperation(delegatingList))
{
command = new DeleteAllOneByOneInBatchesCommand(delegatingList, bSize);
}
else
{
command = new DeleteAllInBatchesTransactionalCommand(delegatingList, this, bSize);
}
executeCommandInBatches("DeleteAllInBatches"+batchSize,bSize, command);
}
public void purgeAllInBatches(DelegatingList delegatingList, int batchSize)
{
verifyNotInTransaction();
final int[] bSize = new int[1];
bSize[0] = batchSize;
TransactionalCommand command;
if (isComplexOperation(delegatingList))
{
throw new RuntimeException("Multiple portal purgeAll not implemented");
}
else
{
command = new PurgeAllInBatchesTransactionalCommand(delegatingList, this, bSize);
}
executeCommandInBatches("PurgeAllInBatches"+batchSize, bSize,command);
}
public void cascadeDeleteAll(DelegatingList delegatingList)
{
Operation op = delegatingList.getOperation();
verifyNonDatedList(op);
if (op instanceof MappedOperation)
{
List result = this.resolveOperation(delegatingList);
if (result.size() > 0)
{
MithraManagerProvider.getMithraManager().executeTransactionalCommand(new CascadeDeleteAllTransactionalCommand(delegatingList));
}
}
else
{
fixOperation(delegatingList);
MithraManagerProvider.getMithraManager().executeTransactionalCommand(new CascadeDeleteAllTransactionalCommand(delegatingList));
}
}
private void fixOperation(DelegatingList delegatingList)
{
Operation op = delegatingList.getOperation();
if (op instanceof RelationshipMultiEqualityOperation)
{
delegatingList.zSetOperation(((RelationshipMultiEqualityOperation)op).getOrCreateMultiEqualityOperation());
}
}
public void purgeAll(DelegatingList delegatingList)
{
Operation op = delegatingList.getOperation();
UnifiedSet portals = new UnifiedSet(3);
op.addDependentPortalsToSet(portals);
TransactionalCommand command;
if (portals.size() > 1)
{
throw new RuntimeException("Multiple portal purgeAll not implemented");
}
else
{
command = new PurgeAllTransactionalCommand(delegatingList, this);
}
MithraManagerProvider.getMithraManager().executeTransactionalCommand(command);
}
public void terminateAll(DelegatingList delegatingList)
{
fixOperation(delegatingList);
MithraManagerProvider.getMithraManager().executeTransactionalCommand(new TerminateAllTransactionalCommand(delegatingList));
}
public void cascadeTerminateAll(DelegatingList delegatingList)
{
fixOperation(delegatingList);
MithraManagerProvider.getMithraManager().executeTransactionalCommand(new CascadeTerminateAllTransactionalCommand(delegatingList));
}
public void cascadeTerminateAllUntil(DelegatingList delegatingList, Timestamp exclusiveUntil)
{
MithraManagerProvider.getMithraManager().executeTransactionalCommand(new CascadeTerminateAllUntilTransactionalCommand(delegatingList, exclusiveUntil));
}
public void copyDetachedValuesToOriginalOrInsertIfNewOrDeleteIfRemoved(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be updated");
}
public void zCopyDetachedValuesDeleteIfRemovedOnly(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be updated");
}
public void cascadeUpdateInPlaceBeforeTerminate(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be updated");
}
public void copyDetachedValuesToOriginalOrInsertIfNewOrTerminateIfRemoved(DelegatingList delegatingList)
{
throw new MithraBusinessException("An operation based list cannot be updated");
}
public void copyDetachedValuesToOriginalUntilOrInsertIfNewUntilOrTerminateIfRemoved(DelegatingList delegatingList, Timestamp exclusiveUntil)
{
throw new MithraBusinessException("An operation based list cannot be updated");
}
protected class CascadeDeleteAllTransactionalCommand implements TransactionalCommand
{
private DelegatingList delegatingList;
public CascadeDeleteAllTransactionalCommand(DelegatingList delegatingList)
{
this.delegatingList = delegatingList;
}
public Object executeTransaction(MithraTransaction tx) throws Throwable
{
delegatingList.zCascadeDeleteRelationships();
deleteAll(delegatingList);
return null;
}
}
public void setBoolean(DelegatingList delegatingList, BooleanAttribute attr, boolean newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, ByteAttribute attr, byte newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, ShortAttribute attr, short newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, CharAttribute attr, char newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, IntegerAttribute attr, int newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, LongAttribute attr, long newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, FloatAttribute attr, float newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, DoubleAttribute attr, double newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, StringAttribute attr, String newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, TimestampAttribute attr, Timestamp newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, DateAttribute attr, Date newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, TimeAttribute attr, Time newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, ByteArrayAttribute attr, byte[] newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, BigDecimalAttribute attr, BigDecimal newValue)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, Attribute attr)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, EmbeddedValueExtractor attr, Object evo)
{
List resolved = this.resolveOperation(delegatingList);
for(int i=0;i delegatingList, int index)
{
List list = resolveOperationAndCopy(delegatingList);
MithraObject toBeRemoved = (MithraObject) list.get(index);
this.removeHandler.removeRelatedObject(toBeRemoved);
list.remove(index);
return (E) toBeRemoved;
}
public void add(DelegatingList delegatingList, int index, E o)
{
this.addHandler.addRelatedObject((MithraTransactionalObject) o);
}
@Override
public MithraDelegatedList getNonPersistentDelegate()
{
return AbstractTransactionalNonOperationBasedList.DEFAULT;
}
public boolean add(DelegatingList delegatingList, E o)
{
this.addHandler.addRelatedObject((MithraTransactionalObject) o);
return true;
}
public boolean addAll(DelegatingList delegatingList, int index, Collection extends E> c)
{
return this.addAll(delegatingList, c);
}
public boolean addAll(DelegatingList delegatingList, Collection extends E> c)
{
for(Iterator it = c.iterator(); it.hasNext(); )
{
Object o = it.next();
this.addHandler.addRelatedObject((MithraTransactionalObject) o);
}
return true;
}
public void clear(DelegatingList delegatingList)
{
for(int i=this.size(delegatingList) - 1;i >=0 ;i--)
{
this.remove(delegatingList, i);
}
}
public boolean remove(DelegatingList delegatingList, Object o)
{
List list = resolveOperation(delegatingList);
for(int i=0;i delegatingList, Collection> c)
{
boolean removed = false;
for(Iterator it = c.iterator(); it.hasNext(); )
{
removed |= this.remove(delegatingList, it.next());
}
return removed;
}
@Override
public boolean retainAll(DelegatingList delegatingList, Collection> c)
{
List list = resolveOperationAndCopy(delegatingList);
FastList newList = FastList.newList(list.size());
for(int i=0;i es)
// {
// asdf: must override remove/set -- will break collections.sort
// }
//
// @Override
// public ListIterator listIterator(DelegatingList es, int index)
// {
// asdf: must override remove/set
// }
@Override
public Iterator iterator(DelegatingList delegatingList)
{
return new IteratorWithRemoveHandler(resolveOperation(delegatingList).iterator());
}
private class IteratorWithRemoveHandler implements Iterator
{
private Iterator delegate;
private E last;
private IteratorWithRemoveHandler(Iterator delegate)
{
this.delegate = delegate;
}
@Override
public boolean hasNext()
{
return delegate.hasNext();
}
@Override
public E next()
{
last = delegate.next();
return last;
}
@Override
public void remove()
{
removeHandler.removeRelatedObject((MithraObject) last);
delegate.remove();
}
}
}