Package com.mobixess.jodb.core.transaction

Source Code of com.mobixess.jodb.core.transaction.TransactionContainer

/*
Copyright (C) 2007  Mobixess Inc. http://www.java-objects-database.com

This file is part of the JODB (Java Objects Database) open source project.

JODB is free software; you can redistribute it and/or modify it under
the terms of version 2 of the GNU General Public License as published
by the Free Software Foundation.

JODB is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
package com.mobixess.jodb.core.transaction;

import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Vector;
import java.util.WeakHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;

import com.mobixess.jodb.core.ITransactionResolver;
import com.mobixess.jodb.core.IllegalClassTypeException;
import com.mobixess.jodb.core.JODBConfig;
import com.mobixess.jodb.core.JODBSessionContainer;
import com.mobixess.jodb.core.JodbIOException;
import com.mobixess.jodb.core.agent.JODBAgent;
import com.mobixess.jodb.core.index.IndexingRecord;
import com.mobixess.jodb.core.index.JODBIndexingAgent;
import com.mobixess.jodb.core.io.IOBase;
import com.mobixess.jodb.core.io.IRandomAccessDataBuffer;
import com.mobixess.jodb.core.io.JODBOperationContext;
import com.mobixess.jodb.core.io.IOBase.ObjectIdentity;
import com.mobixess.jodb.core.io.IRandomAccessBufferFactory.BUFFER_TYPE;
import com.mobixess.jodb.core.transaction.JODBSession.ClassDescriptor;
import com.mobixess.jodb.core.transaction.JODBSession.FieldAndIDRecord;
import com.mobixess.jodb.util.Utils;

/**
* @author Mobixess
*
*/
public class TransactionContainer implements ITranslatedDataSorce{
    private Map<Object, TransactionHandle> _transactionObjects;
    private Map<Object, TransactionHandle> _agentsTransactionObjects;
    private WeakHashMap<ITransactionListener, Object> _transactionListeners = new WeakHashMap<ITransactionListener, Object>();
   
    private JODBSession _session;
   
    private IRandomAccessDataBuffer _newDataBuffer;
    private IRandomAccessDataBuffer _replacementsBuffer;
    private IRandomAccessDataBuffer _rollbackBuffer;
    private ITransactionResolver _transactionResolver;
   
    private int _agentsMode;
   
    private ReentrantReadWriteLock _lock = new ReentrantReadWriteLock();
   
    protected Logger _logger = Utils.getLogger(getClass().getName());
   
   
   
    public TransactionContainer(JODBSession session, ITransactionResolver transactionResolver) {
        super();
        if(JODBConfig.DEBUG){
            _transactionObjects = new LinkedHashMap<Object, TransactionHandle>();
            _agentsTransactionObjects = new LinkedHashMap<Object, TransactionHandle>();
        }else{
            _transactionObjects = new IdentityHashMap<Object, TransactionHandle>();
            _agentsTransactionObjects = new IdentityHashMap<Object, TransactionHandle>();
        }
        _transactionResolver = transactionResolver;
        _lock = session.getBase().getTransactionLock();
        _session = session;
    }
   
    /*package*/ Map<Object, TransactionHandle> getTransactionObjects() {
        return isAgentsMode()?_agentsTransactionObjects:_transactionObjects;
    }
   
    public ITransactionResolver getTransactionResolver() {
        return _transactionResolver;
    }

    public void lockTransaction() throws IOException{
        _lock.writeLock().lock();
        _newDataBuffer = JODBConfig.getRandomAccessBufferFactory().createBuffer("", BUFFER_TYPE.NEW_DATA, true);
       
        _rollbackBuffer = JODBConfig.getRandomAccessBufferFactory().createBuffer("", BUFFER_TYPE.ROLLBACK, true);

        _replacementsBuffer = JODBConfig.getRandomAccessBufferFactory().createBuffer("", BUFFER_TYPE.REPLACEMENTS, true);
    }
   
   
    public TransactionHandle getHandleForObject(Object key){
        // TODO add lock?
        return isAgentsMode()?_agentsTransactionObjects.get(key):_transactionObjects.get(key);
    }

   
    public void resetTranslatedObjects(JODBSession session, long transactionShift){
        if(isAgentsMode()){
            throw new IllegalStateException();
        }
        resetTranslatedObjects0(session, _transactionObjects, transactionShift);
        resetTranslatedObjects0(session, _agentsTransactionObjects, transactionShift);
    }
   
    public void addTransactionListener(ITransactionListener listener){
        synchronized (_transactionListeners) {
            _transactionListeners.put(listener, null);
        }
    }
   
    public void setTransactionResolver(ITransactionResolver transactionResolver)
    {
        _transactionResolver = transactionResolver;
    }
   
    public void removeTransactionListeners(ITransactionListener listener){
        synchronized (_transactionListeners) {
            _transactionListeners.remove(listener);
        }
    }
   
    void fireOnObjectSet(Object object, JODBSession session){
        synchronized (_transactionListeners) {
            Iterator<ITransactionListener> iterator = _transactionListeners.keySet().iterator();
            while (iterator.hasNext()) {
                ITransactionListener element = iterator.next();
                element.onSet(object,session);
            }
        }
    }
   
    void fireOnCommitStarted(Object object, JODBSession session){
        synchronized (_transactionListeners) {
            Iterator<ITransactionListener> iterator = _transactionListeners.keySet().iterator();
            while (iterator.hasNext()) {
                ITransactionListener element = iterator.next();
                element.onCommitStarted(object,session);
            }
        }
    }
   
    void fireOnCommitFinished(Object object, JODBSession session){
        synchronized (_transactionListeners) {
            Iterator<ITransactionListener> iterator = _transactionListeners.keySet().iterator();
            while (iterator.hasNext()) {
                ITransactionListener element = iterator.next();
                element.onCommitFinished(object,session);
            }
        }
    }
   
    private void resetTranslatedObjects0(JODBSession session, Map<Object, TransactionHandle>  transactionObjects, long transactionShift){
        if(transactionObjects.isEmpty()){
            return;
        }
        Iterator<Object> iter = transactionObjects.keySet().iterator();
        while (iter.hasNext()) {
            Object element = iter.next();
            TransactionHandle tHandle = transactionObjects.get(element);
            if(tHandle.isNewObject()){
                PersistentObjectHandle persistentObjectHandle = session.createHandleForObject(element, tHandle.getTransactionOffset()+transactionShift, tHandle.getTranslatedObjectDataMask(),(byte) tHandle.getCyclicalVersionCounter(), tHandle.getIdentityHash()  );
                _session.putObject(element, persistentObjectHandle);
            }
            iter.remove();
        }
        //_transactionObjects.clear();
    }
   
    public void processTranslatedObjectsIndex(JODBOperationContext context, long transactionShift) throws IOException{
        enableAgentMode();
        try{
            Iterator<Object> iter = _transactionObjects.keySet().iterator();
            while (iter.hasNext()) {
                Object element = iter.next();
                TransactionHandle tHandle = _transactionObjects.get(element);
                long offsetId;
                if(tHandle.isNewObject()){
                    offsetId = tHandle.getTransactionOffset()+transactionShift;
                }else{
                    offsetId = tHandle.getHandle().getObjectEntryOffset();
                }
                Vector<IndexingRecord> indexingRecords = tHandle.getIndexes();
                if (indexingRecords != null) {
                    for (int i = 0; i < indexingRecords.size(); i++) {
                        IndexingRecord record = indexingRecords.elementAt(i);
                        ByteBuffer currentValue = record.getPersistedDataBuffer();
                        JODBIndexingAgent indexingAgent = record.getIndexingAgent();
                        if (currentValue.limit() != 0 && !indexingAgent.removeIndex(offsetId, currentValue, null)) {
                            throw new JodbIOException("Illegal index state: can't remove index");
                        }
                        ByteBuffer pendingValue = record.getPendingDataBuffer();
                        if (pendingValue.limit() == 0) {
                            throw new JodbIOException(
                                    "indexing value unavailable for " + offsetId);
                        }
                        indexingAgent.insertIndex(offsetId, pendingValue, context);
                        if(!_agentsTransactionObjects.containsKey(indexingAgent)){
                            try {
                                set(indexingAgent, Integer.MAX_VALUE);
                            } catch (Exception e) {
                                throw new JodbIOException(e);
                            }
                        }
                    }
                }           
            }
        }finally{
            disableAgentMode();
        }
    }

    public void reset(){
        try {
            _newDataBuffer.delete();
            _replacementsBuffer.delete();
            _rollbackBuffer.delete();
            _newDataBuffer = null;
            _replacementsBuffer = null;
            _rollbackBuffer = null;
            _transactionObjects.clear();
            _agentsMode = 0;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }finally{
            _lock.writeLock().unlock();
        }
    }
   
    public void set(Object obj, int depth) throws IllegalClassTypeException, IllegalStateException{
        _lock.readLock().lock();
        try {
            set0(obj, depth, JODBConfig.isGenerateCommitTimeStamp(), JODBConfig.isGenerateModificationTimeStamp(), isAgentsMode()?_agentsTransactionObjects:_transactionObjects);
        } finally{
            _lock.readLock().unlock();
        }
    }
   
    public void runResolve(JODBSessionContainer sessionContainer) throws IOException{
        Iterator<Object> iter = _transactionObjects.keySet().iterator();
        IOBase base = _session.getBase();
        ITransactionResolver transactionResolver = _transactionResolver;
        while (iter.hasNext()) {
            Object element = iter.next();
            TransactionHandle tHandle = _transactionObjects.get(element);
            if(!tHandle.isNewObject()){
                PersistentObjectHandle handle = tHandle.getHandle();
                int activeObjectHash = tHandle.getIdentityHash();
                byte version = (byte) tHandle.getCyclicalVersionCounter();
                ObjectIdentity objectIdentity = base.checkObjectChanged(handle.getObjectEntryOffset(), activeObjectHash, version);
                if(objectIdentity!=null){
                    if(_transactionResolver!=null && !transactionResolver.resolve(element, sessionContainer,null)){
                        iter.remove();
                        continue;
                    }
                    tHandle.setIdentityHash(objectIdentity._hashIdentity);
                    tHandle.setCyclicalVersionCounter(objectIdentity._version);
                }
            }
        }
    }
   
    public boolean isEmpty(){
        return _transactionObjects.size() == 0 && _agentsTransactionObjects.size() == 0;
    }

    private synchronized void set0(Object obj, int depth, boolean creationTS, boolean modificationTS, Map<Object, TransactionHandle> transactionObjects ) throws IllegalClassTypeException{
        if(depth <= 0){
            return;
        }
        if(!isAgentsMode() && obj instanceof JODBAgent){
            throw new IllegalArgumentException("Cannot accept agent object");
        }
        TransactionHandle transObjectHandle = transactionObjects.get(obj);
        if(transObjectHandle != null){
            transObjectHandle.enable_SET_TransactionState();
            setChildren(obj, depth-1,creationTS,modificationTS, transactionObjects);
            return;
        }
        fireOnObjectSet(obj, _session);
        PersistentObjectHandle handle = _session.getHandleForActiveObject(obj);
        if(handle!=null){
            transObjectHandle = new TransactionHandle(handle);
        }else{
            transObjectHandle = new TransactionHandle(creationTS,modificationTS);   
        }
       
        transObjectHandle.setAgentObjectMode( isAgentsMode() );
//        if(JODBConfig.DEBUG){
//            _logger.warning("setting transaction object "+obj);
//        }
        transactionObjects.put(obj, transObjectHandle);
        transObjectHandle.enable_SET_TransactionState();
        setChildren(obj, depth-1,creationTS,modificationTS, transactionObjects);
    }
   
    private void setChildren(Object obj, int depth, boolean creationTS, boolean modificationTS, Map<Object, TransactionHandle> transactionObjects) throws IllegalClassTypeException{
        if(depth <= 0){
            return;
        }
        ClassDescriptor descr = _session.getDescriptorForClass(obj.getClass());
        if (descr.isArray()) {
            if(!descr.isPrimitiveArray()){
                int length = Array.getLength(obj);
                for (int i = 0; i < length; i++) {
                    Object value = Array.get(obj, i);
                    if(value!=null){
                        set0(value, depth, creationTS, modificationTS, transactionObjects);
                    }
                }
            }
        }else{
            FieldAndIDRecord[] fields = descr.getAllFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i]._field;
                if (field.getType().isPrimitive()) {
                    continue;
                }
                try {
                    Object value = field.get(obj);
                    if (value != null) {
                        set0(value, depth, creationTS, modificationTS, transactionObjects);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            }
        }       
    }
   
    public void delete(Object obj, int depth) throws IllegalClassTypeException{
        _lock.readLock().lock();
        try {
            delete0(obj, depth);
        } finally{
            _lock.readLock().unlock();
        }
    }
   
    public synchronized void delete0(Object obj, int depth) throws IllegalClassTypeException{
        if(depth <= 0){
            return;
        }
        TransactionHandle transObjectHandle = _transactionObjects.get(obj);
        if(transObjectHandle != null){
            if(transObjectHandle.isNewObject()){
                _transactionObjects.remove(obj);
            }else{
                transObjectHandle.enable_DELETE_TransactionState();
            }
            deleteChildren(obj, depth-1);
            return;
        }
        PersistentObjectHandle handle = _session.getHandleForActiveObject(obj);
        if(handle!=null){
            transObjectHandle = new TransactionHandle(handle);
            transObjectHandle.enable_DELETE_TransactionState();
            _transactionObjects.put(obj, transObjectHandle);
        }
        deleteChildren(obj, depth-1);
    }
   
    public synchronized void deleteChildren(Object obj, int depth) throws IllegalClassTypeException{
        if(depth <= 0){
            return;
        }
        ClassDescriptor descr = _session.getDescriptorForClass(obj.getClass());
        FieldAndIDRecord[] fields = descr.getAllFields();
        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i]._field;
            if(field.getType().isPrimitive()){
                continue;
            }
            try {
                Object value = field.get(obj);
                if(value!=null){
                    delete0(value, depth);
                }
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
        }
    }
   
    public void resetTransactionBufferToStart() throws IOException{
        _rollbackBuffer.resetToStart();
        _newDataBuffer.resetToStart();
        _replacementsBuffer.resetToStart();
    }
   
    public void resetTransactionBufferToEnd() throws IOException{
        _rollbackBuffer.resetToEnd();
        _newDataBuffer.resetToEnd();
        _replacementsBuffer.resetToEnd();
    }
   
    public IRandomAccessDataBuffer getRollbackDataFile() {
        return _rollbackBuffer;
    }

    public IRandomAccessDataBuffer getTransactionNewDataFile() {
        return _newDataBuffer;
    }

    public IRandomAccessDataBuffer getTransactionReplacementsDataFile() {
        return _replacementsBuffer;
    }
   
    public void enableAgentMode(){
        _agentsMode++;
    }
   
    public void disableAgentMode(){
        _agentsMode--;
        if(_agentsMode<0){
            throw new IllegalStateException();
        }
    }
   
    public boolean isAgentsMode() {
        return _agentsMode!=0;
    }
}
TOP

Related Classes of com.mobixess.jodb.core.transaction.TransactionContainer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.