001: /*
002: * $Id: ServiceXaWrapper.java,v 1.7 2003/12/22 21:00:34 ajzeneski Exp $
003: *
004: * Copyright (c) 2003 The Open For Business Project - www.ofbiz.org
005: *
006: * Permission is hereby granted, free of charge, to any person obtaining a
007: * copy of this software and associated documentation files (the "Software"),
008: * to deal in the Software without restriction, including without limitation
009: * the rights to use, copy, modify, merge, publish, distribute, sublicense,
010: * and/or sell copies of the Software, and to permit persons to whom the
011: * Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included
014: * in all copies or substantial portions of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
017: * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
018: * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
019: * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
020: * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
021: * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
022: * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
023: *
024: */
025: package org.ofbiz.service;
026:
027: import java.util.Map;
028:
029: import javax.transaction.*;
030: import javax.transaction.xa.XAException;
031: import javax.transaction.xa.Xid;
032:
033: import org.ofbiz.base.util.Debug;
034: import org.ofbiz.entity.transaction.GenericXaResource;
035: import org.ofbiz.entity.transaction.TransactionFactory;
036: import org.ofbiz.entity.transaction.TransactionUtil;
037: import org.ofbiz.entity.transaction.GenericTransactionException;
038:
039: /**
040: * ServiceXaWrapper - XA Resource wrapper for running services on commit() or rollback()
041: *
042: * @author <a href="mailto:jaz@ofbiz.org">Andy Zeneski</a>
043: * @version $Revision: 1.7 $
044: * @since 3.0
045: */
046: public class ServiceXaWrapper extends GenericXaResource {
047:
048: public static final String module = ServiceXaWrapper.class
049: .getName();
050:
051: protected DispatchContext dctx = null;
052: protected String rollbackService = null;
053: protected String commitService = null;
054: protected Map rollbackContext = null;
055: protected Map commitContext = null;
056:
057: protected ServiceXaWrapper() {
058: }
059:
060: public ServiceXaWrapper(DispatchContext dctx) {
061: this .dctx = dctx;
062: }
063:
064: /**
065: * Sets the service to run on rollback()
066: * @param serviceName Name of service to run
067: * @param context Context to use when running
068: */
069: public void setCommitService(String serviceName, Map context) {
070: this .commitService = serviceName;
071: this .commitContext = context;
072: }
073:
074: /**
075: * @return The name of the service to run on rollback()
076: */
077: public String getCommitService() {
078: return this .commitService;
079: }
080:
081: /**
082: * @return The context used when running the rollback() service
083: */
084: public Map getCommitContext() {
085: return this .commitContext;
086: }
087:
088: /**
089: * Sets the service to run on rollback()
090: * @param serviceName Name of service to run
091: * @param context Context to use when running
092: */
093: public void setRollbackService(String serviceName, Map context) {
094: this .rollbackService = serviceName;
095: this .rollbackContext = context;
096: }
097:
098: /**
099: * @return The name of the service to run on rollback()
100: */
101: public String getRollbackService() {
102: return this .rollbackService;
103: }
104:
105: /**
106: * @return The context used when running the rollback() service
107: */
108: public Map getRollbackContext() {
109: return this .rollbackContext;
110: }
111:
112: public void enlist() throws XAException {
113: super .enlist();
114: Debug.log("Enlisted in transaction : " + this .toString(),
115: module);
116: }
117:
118: // -- XAResource Methods
119: /**
120: * @see javax.transaction.xa.XAResource#commit(javax.transaction.xa.Xid xid, boolean onePhase)
121: */
122: public void commit(Xid xid, boolean onePhase) throws XAException {
123: Debug.log("ServiceXaWrapper#commit() : " + onePhase + " / "
124: + xid.toString(), module);
125: // the commit listener
126: if (this .active) {
127: Debug.logWarning("commit() called without end()", module);
128: }
129: if (this .xid == null || !this .xid.equals(xid)) {
130: throw new XAException(XAException.XAER_NOTA);
131: }
132:
133: if (this .commitService != null) {
134: // suspend this transaction
135: TransactionManager tm = TransactionFactory
136: .getTransactionManager();
137: Transaction parentTransaction = null;
138: try {
139: parentTransaction = tm.suspend();
140: } catch (SystemException e) {
141: throw new XAException(XAException.XA_RBOTHER);
142: }
143:
144: // invoke the service
145: boolean serviceError = false;
146: try {
147: ModelService model = dctx
148: .getModelService(this .commitService);
149: Map this Context = this .commitContext;
150: if (model.validate) {
151: this Context = model.makeValid(this .commitContext,
152: ModelService.IN_PARAM);
153: }
154: dctx.getDispatcher().runSyncIgnore(this .commitService,
155: this Context);
156: } catch (GenericServiceException e) {
157: Debug.logError(e, "Problem calling sync service : "
158: + this .commitService + " / "
159: + this .commitContext, module);
160: serviceError = true; // don't throw the exception until we resume the transaction
161: }
162:
163: // resume the transaction
164: if (parentTransaction != null) {
165: try {
166: tm.resume(parentTransaction);
167: } catch (InvalidTransactionException e) {
168: Debug.logError(e, module);
169: throw new XAException(XAException.XA_RBOTHER);
170: } catch (IllegalStateException e) {
171: Debug.logError(e, module);
172: throw new XAException(XAException.XA_RBOTHER);
173: } catch (SystemException e) {
174: Debug.logError(e, module);
175: throw new XAException(XAException.XA_RBOTHER);
176: }
177: }
178:
179: // now throw the exception
180: if (serviceError) {
181: throw new XAException(XAException.XA_RBOTHER);
182: }
183: } else {
184: Debug.log("No commit service defined; nothing to do",
185: module);
186: }
187:
188: this .xid = null;
189: this .active = false;
190: }
191:
192: /**
193: * @see javax.transaction.xa.XAResource#rollback(javax.transaction.xa.Xid xid)
194: */
195: public void rollback(Xid xid) throws XAException {
196: Debug.log("ServiceXaWrapper#rollback() : " + xid.toString(),
197: module);
198: // the rollback listener
199: if (this .active) {
200: Debug.logWarning("rollback() called without end()", module);
201: }
202: if (this .xid == null || !this .xid.equals(xid)) {
203: throw new XAException(XAException.XAER_NOTA);
204: }
205:
206: if (this .rollbackService != null) {
207: int currentTxStatus = Status.STATUS_UNKNOWN;
208: try {
209: currentTxStatus = TransactionUtil.getStatus();
210: } catch (GenericTransactionException e) {
211: Debug.logError(e, module);
212: }
213:
214: TransactionManager tm = TransactionFactory
215: .getTransactionManager();
216: Transaction parentTransaction = null;
217: if (currentTxStatus != Status.STATUS_NO_TRANSACTION) {
218: try {
219: parentTransaction = tm.suspend();
220: } catch (SystemException e) {
221: Debug.logError(e, module);
222: }
223: }
224:
225: // invoke the service
226: try {
227: ModelService model = dctx
228: .getModelService(this .rollbackService);
229: Map this Context = this .rollbackContext;
230: if (model.validate) {
231: this Context = model.makeValid(this .rollbackContext,
232: ModelService.IN_PARAM);
233: }
234: dctx.getDispatcher().runAsync(this .rollbackService,
235: this Context, true);
236: } catch (GenericServiceException e) {
237: Debug.logError(e, "Problem calling async service : "
238: + this .rollbackService + " / "
239: + this .rollbackContext, module);
240: }
241:
242: if (parentTransaction != null) {
243: try {
244: tm.resume(parentTransaction);
245: } catch (Exception e) {
246: Debug.logError(e, module);
247: }
248: }
249: } else {
250: Debug.log("No rollback service defined; nothing to do",
251: module);
252: }
253:
254: this .xid = null;
255: this .active = false;
256: }
257:
258: public int prepare(Xid xid) throws XAException {
259: // overriding to log two phase commits
260: Debug.log("ServiceXaWrapper#prepare() : " + xid.toString(),
261: module);
262: int rtn = XA_OK;
263: try {
264: rtn = super .prepare(xid);
265: } catch (XAException e) {
266: Debug.logError(e, module);
267: throw e;
268: }
269: Debug.log("ServiceXaWrapper#prepare() : " + rtn + " / "
270: + (rtn == XA_OK), module);
271: return rtn;
272: }
273: }
|