org.bytesoft.bytetcc.logging.SampleCompensableLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.bytesoft.bytetcc.logging.SampleCompensableLogger.java

Source

/**
 * Copyright 2014-2016 yangming.liu<bytefox@126.com>.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, see <http://www.gnu.org/licenses/>.
 */
package org.bytesoft.bytetcc.logging;

import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.transaction.xa.Xid;

import org.apache.commons.lang3.StringUtils;
import org.bytesoft.bytejta.logging.store.VirtualLoggingSystemImpl;
import org.bytesoft.compensable.CompensableBeanFactory;
import org.bytesoft.compensable.archive.CompensableArchive;
import org.bytesoft.compensable.archive.TransactionArchive;
import org.bytesoft.compensable.aware.CompensableBeanFactoryAware;
import org.bytesoft.compensable.aware.CompensableEndpointAware;
import org.bytesoft.compensable.logging.CompensableLogger;
import org.bytesoft.transaction.archive.XAResourceArchive;
import org.bytesoft.transaction.logging.ArchiveDeserializer;
import org.bytesoft.transaction.logging.LoggingFlushable;
import org.bytesoft.transaction.logging.store.VirtualLoggingListener;
import org.bytesoft.transaction.logging.store.VirtualLoggingRecord;
import org.bytesoft.transaction.logging.store.VirtualLoggingSystem;
import org.bytesoft.transaction.recovery.TransactionRecoveryCallback;
import org.bytesoft.transaction.xa.TransactionXid;
import org.bytesoft.transaction.xa.XidFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SampleCompensableLogger extends VirtualLoggingSystemImpl
        implements CompensableLogger, LoggingFlushable, CompensableBeanFactoryAware, CompensableEndpointAware {
    static final Logger logger = LoggerFactory.getLogger(SampleCompensableLogger.class);

    private CompensableBeanFactory beanFactory;
    private String endpoint;

    public void createTransaction(TransactionArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            byte[] byteArray = deserializer.serialize((TransactionXid) archive.getXid(), archive);
            this.create(archive.getXid(), byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while creating transaction-archive.", rex);
        }
    }

    public void updateTransaction(TransactionArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            byte[] byteArray = deserializer.serialize((TransactionXid) archive.getXid(), archive);
            this.modify(archive.getXid(), byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while modifying transaction-archive.", rex);
        }
    }

    public void deleteTransaction(TransactionArchive archive) {
        try {
            this.delete(archive.getXid());
        } catch (RuntimeException rex) {
            logger.error("Error occurred while deleting transaction-archive.", rex);
        }
    }

    public void createCoordinator(XAResourceArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            byte[] byteArray = deserializer.serialize((TransactionXid) archive.getXid(), archive);
            this.create(archive.getXid(), byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while modifying resource-archive.", rex);
        }
    }

    public void updateCoordinator(XAResourceArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            byte[] byteArray = deserializer.serialize((TransactionXid) archive.getXid(), archive);
            this.modify(archive.getXid(), byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while modifying resource-archive.", rex);
        }
    }

    public void createCompensable(CompensableArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            TransactionXid xid = (TransactionXid) archive.getIdentifier();
            byte[] byteArray = deserializer.serialize(xid, archive);
            this.create(xid, byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while creating compensable-archive.", rex);
        }
    }

    public void updateCompensable(CompensableArchive archive) {
        ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();

        try {
            TransactionXid xid = (TransactionXid) archive.getIdentifier();
            byte[] byteArray = deserializer.serialize(xid, archive);
            this.modify(xid, byteArray);
        } catch (RuntimeException rex) {
            logger.error("Error occurred while modifying compensable-archive.", rex);
        }
    }

    public void recover(TransactionRecoveryCallback callback) {

        final Map<Xid, TransactionArchive> xidMap = new HashMap<Xid, TransactionArchive>();
        final ArchiveDeserializer deserializer = this.beanFactory.getArchiveDeserializer();
        final XidFactory xidFactory = this.beanFactory.getCompensableXidFactory();

        this.traversal(new VirtualLoggingListener() {
            public void recvOperation(VirtualLoggingRecord action) {
                Xid xid = action.getIdentifier();
                int operator = action.getOperator();
                if (VirtualLoggingSystem.OPERATOR_DELETE == operator) {
                    xidMap.remove(xid);
                } else if (xidMap.containsKey(xid) == false) {
                    xidMap.put(xid, null);
                }
            }
        });

        this.traversal(new VirtualLoggingListener() {
            public void recvOperation(VirtualLoggingRecord action) {
                Xid xid = action.getIdentifier();
                if (xidMap.containsKey(xid)) {
                    this.execOperation(action);
                }
            }

            public void execOperation(VirtualLoggingRecord action) {
                Xid identifier = action.getIdentifier();

                TransactionXid xid = xidFactory.createGlobalXid(identifier.getGlobalTransactionId());

                Object obj = deserializer.deserialize(xid, action.getValue());
                if (TransactionArchive.class.isInstance(obj)) {
                    TransactionArchive archive = (TransactionArchive) obj;
                    xidMap.put(identifier, archive);
                } else if (XAResourceArchive.class.isInstance(obj)) {
                    TransactionArchive archive = xidMap.get(identifier);
                    if (archive == null) {
                        logger.error("Error occurred while recovering resource archive: {}", obj);
                        return;
                    }

                    XAResourceArchive resourceArchive = (XAResourceArchive) obj;
                    boolean matched = false;

                    List<XAResourceArchive> remoteResources = archive.getRemoteResources();
                    for (int i = 0; matched == false && remoteResources != null
                            && i < remoteResources.size(); i++) {
                        XAResourceArchive element = remoteResources.get(i);
                        if (resourceArchive.getXid().equals(element.getXid())) {
                            matched = true;
                            remoteResources.set(i, resourceArchive);
                        }
                    }

                    if (matched == false) {
                        remoteResources.add(resourceArchive);
                    }

                } else if (CompensableArchive.class.isInstance(obj)) {
                    TransactionArchive archive = xidMap.get(identifier);
                    if (archive == null) {
                        logger.error("Error occurred while recovering compensable archive: {}", obj);
                        return;
                    }

                    List<CompensableArchive> compensables = archive.getCompensableResourceList();
                    CompensableArchive resourceArchive = (CompensableArchive) obj;

                    // if (VirtualLoggingSystem.OPERATOR_CREATE == action.getOperator()) {
                    // compensables.add(resourceArchive);
                    // } else {
                    boolean matched = false;
                    for (int i = 0; matched == false && compensables != null && i < compensables.size(); i++) {
                        CompensableArchive element = compensables.get(i);
                        if (resourceArchive.getIdentifier().equals(element.getIdentifier())) {
                            matched = true;
                            compensables.set(i, resourceArchive);
                        }
                    }

                    if (matched == false) {
                        compensables.add(resourceArchive);
                    }

                    // }

                }

            }
        });

        for (Iterator<Map.Entry<Xid, TransactionArchive>> itr = xidMap.entrySet().iterator(); itr.hasNext();) {
            Map.Entry<Xid, TransactionArchive> entry = itr.next();
            TransactionArchive archive = entry.getValue();
            if (archive == null) {
                continue;
            } else {
                try {
                    callback.recover(archive);
                } catch (RuntimeException rex) {
                    logger.error("Error occurred while recovering transaction(xid= {}).", archive.getXid(), rex);
                }
            }
        }

    }

    public File getDefaultDirectory() {
        String address = StringUtils.trimToEmpty(this.endpoint);
        File directory = new File(String.format("bytetcc/%s", address.replaceAll("\\:|\\.", "_")));
        if (directory.exists() == false) {
            try {
                directory.mkdirs();
            } catch (SecurityException ex) {
                logger.error("Error occurred while creating directory {}!", directory.getAbsolutePath(), ex);
            }
        }
        return directory;
    }

    public String getLoggingFilePrefix() {
        return "bytetcc-";
    }

    public String getLoggingIdentifier() {
        return "org.bytesoft.bytetcc.logging.sample";
    }

    public void setBeanFactory(CompensableBeanFactory tbf) {
        this.beanFactory = tbf;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

}