All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.gs.fw.common.mithra.list.AbstractTransactionalOperationBasedList Maven / Gradle / Ivy

There is a newer version: 18.1.0
Show newest version

/*
 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 c)
    {
        return this.addAll(delegatingList, c);
    }

    public boolean addAll(DelegatingList delegatingList, Collection 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();
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy