001/*
002 * (C) Copyright 2012 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.storage.sql.jdbc;
020
021import static javax.transaction.xa.XAException.XAER_INVAL;
022import static javax.transaction.xa.XAException.XAER_PROTO;
023import static javax.transaction.xa.XAException.XAER_RMERR;
024
025import java.sql.SQLException;
026
027import javax.transaction.xa.XAException;
028import javax.transaction.xa.XAResource;
029import javax.transaction.xa.Xid;
030
031import org.apache.commons.logging.Log;
032import org.apache.commons.logging.LogFactory;
033
034/**
035 * Adapter for a simple JDBC Connection that gives it the XAResource interface, without actually implementing XA
036 * (prepare does nothing).
037 *
038 * @since 5.7
039 */
040public class XAResourceConnectionAdapter implements XAResource {
041
042    private static final Log log = LogFactory.getLog(XAResourceConnectionAdapter.class);
043
044    protected JDBCConnection owner;
045
046    protected Xid xid;
047
048    public XAResourceConnectionAdapter(JDBCConnection connection) {
049        owner = connection;
050    }
051
052    @Override
053    public void start(Xid xid, int flag) throws XAException {
054        if (flag == TMNOFLAGS) {
055            if (this.xid != null) {
056                throw newXAException(XAER_PROTO, "Already started");
057            }
058            this.xid = xid;
059        } else {
060            // cannot support resume
061            throw newXAException(XAER_INVAL, "Invalid flag: " + flag);
062        }
063    }
064
065    @Override
066    public void end(Xid xid, int flag) throws XAException {
067        if (xid != this.xid) {
068            throw newXAException(XAER_INVAL, "Invalid Xid");
069        }
070        if (flag != TMSUCCESS && flag != TMFAIL) {
071            throw newXAException(XAER_INVAL, "Invalid flag: " + flag);
072        }
073    }
074
075    @Override
076    public int prepare(Xid xid) throws XAException {
077        return XA_OK;
078    }
079
080    @Override
081    public void commit(Xid xid, boolean flag) throws XAException {
082        if (this.xid == null || !this.xid.equals(xid)) {
083            throw newXAException(XAER_INVAL, "Invalid Xid");
084        }
085        this.xid = null;
086        try {
087            owner.connection.commit();
088        } catch (SQLException e) {
089            throw newXAException(XAER_RMERR, "Cannot commit", e);
090        }
091    }
092
093    @Override
094    public void rollback(Xid xid) throws XAException {
095        if (this.xid == null || !this.xid.equals(xid)) {
096            throw newXAException(XAER_INVAL, "Invalid Xid");
097        }
098        this.xid = null;
099        try {
100            owner.connection.rollback();
101        } catch (SQLException e) {
102            throw newXAException(XAER_RMERR, "Cannot rollback", e);
103        }
104    }
105
106    @Override
107    public void forget(Xid xid) throws XAException {
108        throw newXAException(XAER_PROTO, "Unsupported method");
109    }
110
111    @Override
112    public Xid[] recover(int n) throws XAException {
113        return new Xid[0];
114    }
115
116    @Override
117    public int getTransactionTimeout() throws XAException {
118        return 0;
119    }
120
121    @Override
122    public boolean setTransactionTimeout(int txTimeout) throws XAException {
123        return false;
124    }
125
126    @Override
127    public boolean isSameRM(XAResource xares) throws XAException {
128        return this == xares;
129    }
130
131    protected static XAException newXAException(int errorCode, String message, Exception cause) {
132        return (XAException) newXAException(errorCode, message).initCause(cause);
133    }
134
135    protected static XAException newXAException(int errorCode, String message) {
136        XAException e = new XAException(message);
137        e.errorCode = errorCode;
138        return e;
139    }
140
141}