001: /*
002: * Copyright 2004-2006 the original author or authors.
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:
017: package org.compass.core.transaction;
018:
019: import javax.transaction.Transaction;
020: import javax.transaction.UserTransaction;
021: import javax.transaction.xa.XAException;
022: import javax.transaction.xa.XAResource;
023: import javax.transaction.xa.Xid;
024:
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027: import org.compass.core.engine.SearchEngine;
028: import org.compass.core.spi.InternalCompassSession;
029:
030: /**
031: * <p>Allows for Compass to particiapte in a two phase commit transaction using
032: * JTA.
033: *
034: * <p>Enlists an {@link javax.transaction.xa.XAResource} Compass implementation
035: * with a current JTA {@link javax.transaction.Transaction}.
036: *
037: * <p>Transaction management is done by {@link org.compass.core.transaction.XATransactionFactory}
038: * so there is no need to implement suspend and resume (works the same way
039: * {@link org.compass.core.transaction.JTASyncTransaction} does).
040: *
041: * @author kimchy
042: */
043: public class XATransaction extends AbstractJTATransaction {
044:
045: public XATransaction(UserTransaction ut,
046: TransactionFactory transactionFactory) {
047: super (ut, transactionFactory);
048: }
049:
050: protected void doBindToTransaction(Transaction tx,
051: InternalCompassSession session, boolean newTransaction)
052: throws Exception {
053: tx.enlistResource(new CompassXAResource(session));
054: }
055:
056: private static class CompassXAResource implements XAResource {
057:
058: private static final Log log = LogFactory
059: .getLog(CompassXAResource.class);
060:
061: private InternalCompassSession session;
062:
063: private SearchEngine searchEngine;
064:
065: public CompassXAResource(InternalCompassSession session) {
066: this .session = session;
067: this .searchEngine = session.getSearchEngine();
068: }
069:
070: public int getTransactionTimeout() throws XAException {
071: return 0;
072: }
073:
074: public boolean setTransactionTimeout(int i) throws XAException {
075: // TODO support transaction timeout
076: return false;
077: }
078:
079: public boolean isSameRM(XAResource xares) throws XAException {
080: return (xares != null && xares instanceof CompassXAResource && session == ((CompassXAResource) xares).session);
081: }
082:
083: public Xid[] recover(int i) throws XAException {
084: return null;
085: }
086:
087: public void forget(Xid xid) throws XAException {
088: session.close();
089: }
090:
091: public void start(Xid xid, int flags) throws XAException {
092: switch (flags) {
093: case TMJOIN:
094: case TMRESUME:
095: // no need to resume anything, the outer
096: // transaction factory manages it
097: case TMNOFLAGS:
098: // no need to start the transaction here
099: // since we already started it in the base class
100: default:
101: break;
102: }
103: }
104:
105: public void end(Xid xid, int flags) throws XAException {
106: // nothing here to do
107: switch (flags) {
108: case TMSUSPEND:
109: break;
110: case TMFAIL:
111: break;
112: case TMSUCCESS:
113: break;
114: }
115: }
116:
117: public int prepare(Xid xid) throws XAException {
118: try {
119: searchEngine.prepare();
120: } catch (Exception e) {
121: log.error(
122: "Failed to prepare transaction [" + xid + "]",
123: e);
124: throw new XAException(e.getMessage());
125: }
126: if (searchEngine.isReadOnly()) {
127: commit(xid, false);
128: return XA_RDONLY;
129: }
130: return XA_OK;
131: }
132:
133: public void commit(Xid xid, boolean onePhase)
134: throws XAException {
135: if (searchEngine.wasRolledBack()) {
136: throw new XAException(XAException.XA_RBROLLBACK);
137: }
138: try {
139: searchEngine.commit(onePhase);
140: } catch (Exception e) {
141: log.error("Failed to commit transaction [" + xid + "]",
142: e);
143: throw new XAException(e.getMessage());
144: }
145: }
146:
147: public void rollback(Xid xid) throws XAException {
148: try {
149: searchEngine.rollback();
150: } catch (Exception e) {
151: log.error("Failed to rollback transaction [" + xid
152: + "]", e);
153: throw new XAException(e.getMessage());
154: }
155: }
156: }
157: }
|