001: /*
002: * JacORB - a free Java ORB
003: *
004: * Copyright (C) 1999-2004 Gerald Brose
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Library General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Library General Public License for more details.
015: *
016: * You should have received a copy of the GNU Library General Public
017: * License along with this library; if not, write to the Free
018: * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
019: *
020: */
021: package org.jacorb.transaction;
022:
023: import org.apache.avalon.framework.logger.Logger;
024:
025: import org.omg.CosTransactions.*;
026: import org.omg.CosNaming.*;
027: import org.omg.IOP.*;
028: import org.jacorb.orb.ORB;
029: import org.omg.CORBA.Any;
030: import java.util.*;
031:
032: /**
033: * This class represents the transaction current.
034: * It is a very simple implementation wich mostly
035: * maps to the methods in the control.
036: *
037: * @author Nicolas Noffke
038: * @author Vladimir Mencl
039: * @version $Id: TransactionCurrentImpl.java,v 1.17 2005/11/20 13:48:16 andre.spiegel Exp $
040: */
041:
042: public class TransactionCurrentImpl extends org.omg.CORBA.LocalObject
043: implements Current {
044: private static final int DEFAULT_TIMEOUT = 30;
045:
046: private Hashtable contexts = null;
047: private Hashtable timeouts = null;
048: private ORB orb = null;
049: private static int slot_id = -1; /* used from static getControl */
050:
051: /** there will only be ony logger instance for all TX services in a process...*/
052: private static Logger logger;
053:
054: private TransactionFactory factory = null;
055:
056: public TransactionCurrentImpl(ORB orb, int slot_id) {
057: this .orb = orb;
058: this .slot_id = slot_id;
059: logger = orb.getConfiguration().getNamedLogger(
060: "jacorb.tx_service.current");
061:
062: contexts = new Hashtable();
063: timeouts = new Hashtable();
064:
065: try {
066: NamingContextExt nc = NamingContextExtHelper.narrow(orb
067: .resolve_initial_references("NameService"));
068: NameComponent[] name = new NameComponent[1];
069: name[0] = new NameComponent("TransactionService", "service");
070: factory = TransactionFactoryHelper.narrow(nc.resolve(name));
071: } catch (Exception e) {
072: if (logger.isErrorEnabled())
073: logger
074: .error(
075: "Unable to obtain Transaction Service reference. Giving up.",
076: e);
077: throw new Error(e.getMessage());
078: }
079: }
080:
081: /**
082: * Creates a non-functional current.
083: */
084: public TransactionCurrentImpl() {
085: contexts = new Hashtable();
086: timeouts = new Hashtable();
087: }
088:
089: /**
090: * This method is a convenience method for the server
091: * programmer the exctract the Control from the
092: * PICurrent.
093: */
094: public static Control getControl(org.omg.CORBA.ORB orb) {
095: try {
096: org.omg.PortableInterceptor.Current pi_current = (org.omg.PortableInterceptor.Current) orb
097: .resolve_initial_references("PICurrent");
098:
099: PropagationContext context = PropagationContextHelper
100: .extract(pi_current.get_slot(slot_id));
101:
102: return ControlHelper
103: .extract(context.implementation_specific_data);
104: } catch (Exception e) {
105: if (logger.isDebugEnabled())
106: logger
107: .debug(
108: "Unable to obtain Transaction Service reference. Giving up.",
109: e);
110: }
111:
112: return null;
113: }
114:
115: // implementation of org.omg.CosTransactions.CurrentOperations interface
116: /**
117: * Start a new transaction. The propagation context will be transfered
118: * on ALL communication (~1k extra data) from now on, until
119: * the transaction is committed or rolled back. <br>
120: * NOTICE: the PropagationContext might not be set up fully
121: * compliant to the Spec.
122: */
123: public void begin() throws SubtransactionsUnavailable {
124: Thread thread = Thread.currentThread();
125:
126: if (contexts.containsKey(thread))
127: throw new SubtransactionsUnavailable();
128:
129: int timeout = (timeouts.containsKey(thread)) ? ((Integer) timeouts
130: .get(thread)).intValue()
131: : DEFAULT_TIMEOUT;
132:
133: Control control = factory.create(timeout);
134: contexts.put(thread, control);
135:
136: try {
137: org.omg.PortableInterceptor.Current pi_current = (org.omg.PortableInterceptor.Current) orb
138: .resolve_initial_references("PICurrent");
139:
140: // the info inserted here is actually never needed and mostly a waste of
141: // space/bandwidth, since the control itself is transfered also.
142: TransIdentity id = new TransIdentity(control
143: .get_coordinator(), control.get_terminator(),
144: new otid_t(0, 0, new byte[0]));
145:
146: Any control_any = orb.create_any();
147: ControlHelper.insert(control_any, control);
148:
149: PropagationContext context = new PropagationContext(
150: timeout, id, new TransIdentity[0], control_any);
151: Any context_any = orb.create_any();
152: PropagationContextHelper.insert(context_any, context);
153:
154: pi_current.set_slot(slot_id, context_any);
155: } catch (Exception e) {
156: if (logger.isDebugEnabled())
157: logger.debug("Exception: ", e);
158: }
159: }
160:
161: public void commit(boolean report_heuristics) throws NoTransaction,
162: HeuristicMixed, HeuristicHazard {
163: Thread current = Thread.currentThread();
164:
165: if (!contexts.containsKey(current))
166: throw new NoTransaction();
167:
168: Control control = null;
169: try {
170: control = (Control) contexts.get(current);
171: control.get_terminator().commit(report_heuristics);
172: control._release();
173:
174: removeContext(current);
175: } catch (org.omg.CORBA.TRANSACTION_ROLLEDBACK tr) {
176: // Transaction was rolledback.
177: if (logger.isDebugEnabled())
178: logger.debug("TRANSACTION_ROLLEDBACK: ", tr);
179:
180: control._release();
181: removeContext(current);
182: throw tr; // re-throw the exception
183: } catch (Exception e) {
184: if (logger.isDebugEnabled())
185: logger.debug("Exception: ", e);
186: }
187: }
188:
189: /**
190: * This and the following method should actually throw
191: * NoTransaction, but that is against the spec.
192: */
193: public Control get_control() {
194: return (Control) contexts.get(Thread.currentThread());
195: }
196:
197: public Status get_status() {
198: Thread current = Thread.currentThread();
199:
200: if (!contexts.containsKey(current))
201: return null;
202:
203: try {
204: return ((Control) contexts.get(current)).get_coordinator()
205: .get_status();
206: } catch (Exception e) {
207: if (logger.isDebugEnabled())
208: logger.debug("Exception: ", e);
209: }
210: return null;
211: }
212:
213: public String get_transaction_name() {
214: Thread current = Thread.currentThread();
215:
216: if (!contexts.containsKey(current))
217: return null;
218:
219: try {
220: return ((Control) contexts.get(current)).get_coordinator()
221: .get_transaction_name();
222: } catch (Exception e) {
223: if (logger.isDebugEnabled())
224: logger.debug("Exception: ", e);
225: }
226: return null;
227: }
228:
229: public void resume(Control which) throws InvalidControl {
230: setCurrentThreadContext(which);
231: }
232:
233: public void rollback() throws NoTransaction {
234: Thread current = Thread.currentThread();
235:
236: if (!contexts.containsKey(current))
237: throw new NoTransaction();
238: try {
239: Control control = (Control) contexts.get(current);
240: control.get_terminator().rollback();
241:
242: control._release();
243:
244: removeContext(current);
245: } catch (Exception e) {
246: if (logger.isDebugEnabled())
247: logger.debug("Exception: ", e);
248: }
249: }
250:
251: public void rollback_only() throws NoTransaction {
252: Thread current = Thread.currentThread();
253:
254: if (!contexts.containsKey(current))
255: throw new NoTransaction();
256: try {
257: Control control = (Control) contexts.get(current);
258: control.get_coordinator().rollback_only();
259: control._release();
260:
261: removeContext(current);
262: } catch (Exception e) {
263: if (logger.isDebugEnabled())
264: logger.debug("Exception: ", e);
265: }
266: }
267:
268: public void set_timeout(int seconds) {
269: timeouts.put(Thread.currentThread(), new Integer(seconds));
270: }
271:
272: public Control suspend() {
273: Control result = get_control();
274: removeContext(Thread.currentThread());
275: return result;
276: }
277:
278: public void setCurrentThreadContext(Control control) {
279: Thread thread = Thread.currentThread();
280:
281: contexts.put(thread, control);
282:
283: try {
284: org.omg.PortableInterceptor.Current pi_current = (org.omg.PortableInterceptor.Current) orb
285: .resolve_initial_references("PICurrent");
286:
287: // the info inserted here is actually never needed and mostly a waste of
288: // space/bandwidth, since the control itself is transfered also.
289: TransIdentity id = new TransIdentity(control
290: .get_coordinator(), control.get_terminator(),
291: new otid_t(0, 0, new byte[0]));
292:
293: Any control_any = orb.create_any();
294: ControlHelper.insert(control_any, control);
295:
296: int timeout = (timeouts.containsKey(thread)) ? ((Integer) timeouts
297: .get(thread)).intValue()
298: : DEFAULT_TIMEOUT;
299:
300: PropagationContext context = new PropagationContext(
301: timeout, id, new TransIdentity[0], control_any);
302:
303: Any context_any = orb.create_any();
304: PropagationContextHelper.insert(context_any, context);
305: pi_current.set_slot(slot_id, context_any);
306: } catch (Exception e) {
307: if (logger.isDebugEnabled())
308: logger.debug("Exception: ", e);
309: }
310: }
311:
312: private void removeContext(Thread current) {
313: //remove control from Hashtable
314: contexts.remove(current);
315:
316: try {
317: org.omg.PortableInterceptor.Current pi_current = (org.omg.PortableInterceptor.Current) orb
318: .resolve_initial_references("PICurrent");
319:
320: //remove control from PICurrent by overwriting it with
321: //an empty any
322: Any empty = orb.create_any();
323: pi_current.set_slot(slot_id, empty);
324: } catch (Exception e) {
325: if (logger.isDebugEnabled())
326: logger.debug("Exception: ", e);
327: }
328: }
329: } // TransactionCurrentImpl
|