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

org.jboss.jbossts.star.resource.Transaction Maven / Gradle / Ivy

/*
 * JBoss, Home of Professional Open Source
 * Copyright 2010, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags.
 * See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 * 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, v. 2.1.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * 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,
 * v.2.1 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * (C) 2010
 * @author JBoss Inc.
 */
package org.jboss.jbossts.star.resource;

import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;

import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import com.arjuna.ats.arjuna.common.Uid;
import org.jboss.jbossts.star.provider.HttpResponseException;
import org.jboss.jbossts.star.service.Coordinator;
import org.jboss.jbossts.star.util.TxMediaType;
import org.jboss.jbossts.star.util.TxStatus;

import com.arjuna.ats.arjuna.AtomicAction;
import com.arjuna.ats.arjuna.coordinator.AbstractRecord;
import com.arjuna.ats.arjuna.coordinator.AddOutcome;
import com.arjuna.ats.arjuna.coordinator.RecordListIterator;
import org.jboss.jbossts.star.util.TxSupport;
import org.jboss.jbossts.star.util.media.txstatusext.CoordinatorElement;
import org.jboss.jbossts.star.util.media.txstatusext.TransactionStatusElement;
import org.jboss.jbossts.star.util.media.txstatusext.TwoPhaseAwareParticipantElement;
import org.jboss.logging.Logger;

@XmlRootElement(name = "transaction")
public class Transaction extends AtomicAction {
    protected static final Logger log = Logger.getLogger(Transaction.class);

    private long age = System.currentTimeMillis();
    private Coordinator coordinator = null;
    private String initiator;
    private String recoveryUrl = null;
    private Collection volatileParticipants; // synchronizations

    public Transaction() {
        super();
        volatileParticipants = new ArrayList();
    }

    public Transaction(Coordinator coordinator, String initiator) {
        this();
        this.coordinator = coordinator;
        this.initiator = initiator;
    }

    public Transaction(Uid uid) {
        super(uid);
        volatileParticipants = new ArrayList();
    }

    public CoordinatorElement toXML() {
        CoordinatorElement coordinatorElement = new CoordinatorElement();

        coordinatorElement.setCreated(new Date(System.currentTimeMillis() - age));
        coordinatorElement.setStatus(TransactionStatusElement.valueOf(getStatus()));
        coordinatorElement.setTimeout(getTimeout());

        for (String vParticipant : volatileParticipants)
            coordinatorElement.addVolatileParticipant(vParticipant);

        return coordinatorElement;
    }

    @XmlElement
    public String getInitiator() {
        return initiator;
    }

    @XmlElement
    public String getAge() {
        return Long.toString(System.currentTimeMillis() - age);
    }

    @XmlAttribute
    public String getStatus() {
        return getStatus(lookupStatus());
    }

    protected int lookupStatus() {
        return status();
    }

    public String getStatus(int status) {
        TxStatus txStatus = TxStatus.fromActionStatus(status);

        if (txStatus.equals(TxStatus.TransactionStatusUnknown))
            return ""; //ActionStatus.stringForm(lookupStatus());

        return txStatus.name();
    }

    public TxStatus getTxStatus() {
        return TxStatus.fromActionStatus(lookupStatus());
    }

    public String getRecoveryUrl() {
        return recoveryUrl;
    }

    public String enlistParticipant(String coordinatorUrl, String participantUrl, String recoveryUrlBase,
                                    String terminateUrl) {
        if (findParticipant(participantUrl) != null)
            return null;    // already enlisted

        String txId = get_uid().fileStringForm();
        RESTRecord p = new RESTRecord(txId, coordinatorUrl, participantUrl, terminateUrl);
        String coordinatorId = p.get_uid().fileStringForm();

        recoveryUrl = recoveryUrlBase + txId + '/' + coordinatorId;
        p.setRecoveryURI(recoveryUrl);

        if (add(p) != AddOutcome.AR_REJECTED)
            return coordinatorId;

        return null;
    }

    public String enlistParticipant(String coordinatorUrl, String participantUrl, String recoveryUrlBase,
                                    String commitURI, String prepareURI, String rollbackURI, String commitOnePhaseURI) {
        if (findParticipant(participantUrl) != null)
            return null;    // already enlisted

        String txId = get_uid().fileStringForm();
        RESTRecord p = new RESTRecord(txId, coordinatorUrl, participantUrl,
                commitURI, prepareURI, rollbackURI, commitOnePhaseURI);
        String coordinatorId = p.get_uid().fileStringForm();

        recoveryUrl = recoveryUrlBase + txId + '/' + coordinatorId;
        p.setRecoveryURI(recoveryUrl);

        if (add(p) != AddOutcome.AR_REJECTED)
            return coordinatorId;

        return null;
    }
    /**
     * Determine whether a participant is enlisted in this transaction and the commitment
     * is not running.
     *
     * @param participantUrl the participant url to search for
     * @return false if the participant is not enlisted or if the commitment protocol is
     * already running
     */
    public boolean isEnlisted(String participantUrl) {
        return findParticipant(participantUrl) != null;
    }

    public boolean forgetParticipant(String participantUrl) {
        RESTRecord rr = findParticipant(participantUrl);

        if (rr != null)
            return pendingList.remove(rr);

        return false;
    }

    public void getParticipants(Collection enlistmentIds) {
        if (pendingList == null)
            return;

        // only add faults for pending records
        AbstractRecord r = pendingList.peekFront();

        while (r != null)
        {
            if (r instanceof RESTRecord)
                enlistmentIds.add(r.get_uid().fileStringForm());

            r = pendingList.peekNext(r);
        }
    }

    public void setFault(String fault) {
        if (pendingList == null)
            return;

        // only add faults for pending records
        AbstractRecord r = pendingList.peekFront();

        while (r != null)
        {
            if (r instanceof RESTRecord)
                ((RESTRecord) r).setFault(fault);

            r = pendingList.peekNext(r);
        }
    }

    public boolean isFinishing() {
        return getTxStatus().isFinishing();
    }
    public boolean isAlive() {
        return getTxStatus().isActive();
    }

    public boolean isRunning() {
        return getTxStatus().isRunning();
    }


    private RESTRecord findParticipant(String participantUrl) {
        if (pendingList != null) {
            RecordListIterator i = new RecordListIterator(pendingList);
            AbstractRecord r;

            while ((r = i.iterate()) != null) {
                if (r instanceof RESTRecord) {
                    RESTRecord rr = (RESTRecord) r;

                    if (rr.getParticipantURI().equals(participantUrl))
                        return rr;
                }
            }
        }

        return null;
    }

    public boolean getStatus(TwoPhaseAwareParticipantElement participantElement, String participantUrl) {
        RESTRecord rr = findParticipant(participantUrl);

        if (rr == null)
            return false;

        try {
            participantElement.setStatus(TransactionStatusElement.valueOf(rr.getStatus()));
        } catch (IllegalArgumentException e) {
            participantElement.setStatus(TransactionStatusElement.TransactionStatusNone);
        }
        participantElement.setCreated(new Date(rr.getAge()));

        return true;
    }

    public void addVolatileParticipant(String vparticipantURI) {
        volatileParticipants.add(vparticipantURI);
    }

    private Collection enlistmentIds;
    @Override
    protected boolean beforeCompletion() {
        boolean commit = true;

        // NB volatileParticipants cannot change once 2PC has commenced

        for (String uri : volatileParticipants) {
            try {
                new TxSupport().httpRequest(new int[] {HttpURLConnection.HTTP_OK}, uri, "PUT", null);
            } catch (HttpResponseException e) {
                commit = false;

                if (log.isDebugEnabled())
                    log.debugf(e, "volatile participant %s error %s during beforeCompletion", uri, e.getMessage());
            }
        }

        if (!super.beforeCompletion())
            commit = false;

        // Get a list of the participants before they check-out of the transaction
        enlistmentIds = new ArrayList();
        getParticipants(enlistmentIds);

        return commit;
    }

    @Override
    protected boolean afterCompletion(int arjunaStatus) {
        return afterCompletion(arjunaStatus, false);
    }

    @Override
    protected boolean afterCompletion(int arjunaStatus, boolean report_heuristics) {
        // NB volatileParticipants collection cannot change once 2PC has commenced

        if (volatileParticipants.size() != 0) {
            String status = TxSupport.toStatusContent(TxStatus.fromActionStatus(arjunaStatus).name());

            for (String uri : volatileParticipants) {
                try {
                    new TxSupport().httpRequest(new int[] {HttpURLConnection.HTTP_OK},
                            uri, "PUT", TxMediaType.TX_STATUS_MEDIA_TYPE, status);
                } catch (HttpResponseException e) {
                    if (log.isDebugEnabled())
                        log.debugf(e, "volatile participant %s error %s during afterCompletion", uri, e.getMessage());
                }
            }
        }

        if (failedList == null || failedList.size() == 0) {
            coordinator.removeTxState(arjunaStatus, this, enlistmentIds);
        }

        return super.afterCompletion(arjunaStatus, report_heuristics);
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy