001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or 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: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: TransactionServiceImpl.java 7293 2005-08-24 21:41:52Z ehardesty $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas.jtm;
025:
026: import java.rmi.RemoteException;
027:
028: import javax.management.MBeanServer;
029: import javax.management.ObjectName;
030: import javax.management.modelmbean.ModelMBean;
031: import javax.naming.Context;
032: import javax.naming.InitialContext;
033: import javax.naming.NamingException;
034: import javax.transaction.UserTransaction;
035: import javax.transaction.xa.Xid;
036:
037: import org.apache.commons.modeler.ManagedBean;
038: import org.apache.commons.modeler.Registry;
039:
040: import org.objectweb.jotm.Current;
041: import org.objectweb.jotm.TransactionFactory;
042: import org.objectweb.jotm.TransactionFactoryImpl;
043: import org.objectweb.transaction.jta.TransactionManager;
044:
045: import org.objectweb.jonas.common.Log;
046: import org.objectweb.jonas.jmx.J2eeObjectName;
047: import org.objectweb.jonas.jmx.JmxService;
048: import org.objectweb.jonas.jmx.JonasObjectName;
049: import org.objectweb.jonas.management.JonasMBeanTools;
050: import org.objectweb.jonas.naming.NamingManager;
051: import org.objectweb.jonas.service.AbsServiceImpl;
052: import org.objectweb.jonas.service.ServiceException;
053: import org.objectweb.jonas.service.ServiceManager;
054:
055: import org.objectweb.util.monolog.api.BasicLevel;
056: import org.objectweb.util.monolog.api.Logger;
057:
058: /**
059: * Transaction Service implementation.
060: * This singleton class must exist in each jonas server.
061: * This class manages a unique Current object that implements both
062: * TransactionManager and UserTransaction interfaces.
063: * @author Philippe Durieux
064: * Contributor(s): Adriana Danes
065: */
066: public class TransactionServiceImpl extends AbsServiceImpl implements
067: TransactionService, TransactionServiceImplMBean {
068:
069: private static Logger logger = null;
070:
071: /**
072: * Service name as used to label configuration properties
073: */
074: public static final String SERVICE_NAME = "jtm";
075: // Transaction Service configuration properties
076: /**
077: * name of the 'timeout' configuration parameter
078: */
079: static final String TIMEOUT = "jonas.service.jtm.timeout";
080: /**
081: * name of the 'remote' configuration parameter
082: */
083: static final String REMOTE = "jonas.service.jtm.remote";
084: /**
085: * name of the 'class' configuration parameter
086: */
087: static final String CLASS = "jonas.service.jtm.class";
088:
089: /**
090: /* TM factory may be local or remote.
091: /* The TM factory is used by the JTA implementation when transactions
092: /* are distributed among several JVM (JOnAS Server or applet client)
093: */
094: private TransactionFactory tm = null;
095:
096: /**
097: * Unique Current object implementing the standard TransactionManager
098: /* set to null while service is not started.
099: */
100: private Current current = null;
101:
102: private Xid[] myXid = null;
103:
104: // Configuration information used to start the Transaction service
105: private int timeout;
106: private boolean jtmlocal;
107: private InitialContext ictx;
108:
109: /**
110: * Registry object containing the information declared in mbean-descriptors configuration files
111: */
112: private Registry oRegistry = null;
113: /**
114: * Reference of the current MBean server needed to register MBeans
115: */
116: private MBeanServer mbeanServer = null;
117:
118: // -------------------------------------------------------------------
119: // JOnAS Service Implementation
120: // -------------------------------------------------------------------
121:
122: /**
123: * Init the Service.
124: * Configuration information is passed thru a Context object.
125: * @param ctx naming context containing configuration parameters
126: * @throws ServiceException if service initialization failes
127: */
128: public void doInit(Context ctx) throws ServiceException {
129:
130: // get logger for this service
131: logger = Log.getLogger(Log.JONAS_SERVER_PREFIX);
132: super .initLogger(Log.getLogger(Log.JONAS_MANAGEMENT_PREFIX));
133:
134: // Gets the configuration
135: String remote = "false";
136: try {
137: remote = (String) ctx.lookup(REMOTE);
138: } catch (NamingException e) {
139: // No problem if there is no value --> default value
140: }
141: if ((remote != null) && (!remote.equals(""))) {
142: jtmlocal = !remote.equalsIgnoreCase("true");
143: } else {
144: jtmlocal = false;
145: }
146:
147: String tstr = "60";
148: try {
149: tstr = (String) ctx.lookup(TIMEOUT);
150: } catch (NamingException e) {
151: // No problem if there is no value --> default value
152: }
153: if ((tstr != null) && (!tstr.equals(""))) {
154: timeout = (new Integer(tstr)).intValue();
155: } else {
156: timeout = 60;
157: }
158:
159: // Get the JMX Server via JMX Service
160: try {
161: mbeanServer = ((JmxService) ServiceManager.getInstance()
162: .getJmxService()).getJmxServer();
163: } catch (Exception e) {
164: // the JMX service may not be started
165: mbeanServer = null;
166: }
167: // Use Jakarta Common Modeler API
168: oRegistry = JonasMBeanTools.getRegistry();
169:
170: if (logger.isLoggable(BasicLevel.DEBUG)) {
171: logger.log(BasicLevel.DEBUG,
172: "TransactionService initialized. Timeout = "
173: + timeout);
174: }
175: }
176:
177: /**
178: * Start the Service
179: * Initialization of the service is already done.
180: * @throws ServiceException if service start fails
181: */
182: public void doStart() throws ServiceException {
183: try {
184: ictx = NamingManager.getInstance().getInitialContext();
185: } catch (NamingException e) {
186: logger.log(BasicLevel.ERROR,
187: "TransactionService: Cannot get InitialContext:\n"
188: + e);
189: throw new ServiceException(
190: "TransactionService: Cannot get InitialContext", e);
191: }
192:
193: // Gets the Distributed Transaction Manager (JTM)
194: if (jtmlocal) {
195: // Creates a JTM locally in this server
196: if (logger.isLoggable(BasicLevel.DEBUG)) {
197: logger
198: .log(BasicLevel.DEBUG,
199: "working with a colocated Transaction Manager ");
200: }
201:
202: // TODO: Recovery of the JTM
203:
204: // Creates the ControlFactory and register it in JNDI.
205: try {
206: if (logger.isLoggable(BasicLevel.DEBUG)) {
207: logger.log(BasicLevel.DEBUG,
208: "Create and register TM factory");
209: }
210: tm = new TransactionFactoryImpl();
211: ictx.rebind("TMFactory", tm);
212: } catch (RemoteException e) {
213: logger.log(BasicLevel.ERROR,
214: "TransactionService: Cannot create TransactionFactory:\n"
215: + e);
216: throw new ServiceException(
217: "TransactionService: Cannot create TransactionFactory",
218: e);
219: } catch (NamingException e) {
220: logger.log(BasicLevel.ERROR,
221: "TransactionService: Cannot rebind TM:\n" + e);
222: throw new ServiceException(
223: "TransactionService: Cannot rebind TM", e);
224: }
225: } else {
226: // JTM is remote, finds it by JNDI
227: if (logger.isLoggable(BasicLevel.DEBUG)) {
228: logger.log(BasicLevel.DEBUG,
229: "working with a remote Transaction Manager ");
230: }
231: final int maxloops = 5;
232: for (int i = 0; i <= maxloops; i++) {
233: try {
234: tm = (TransactionFactory) ictx.lookup("TMFactory");
235: break;
236: } catch (NamingException e) {
237: if (i < maxloops) {
238: logger.log(BasicLevel.WARN,
239: "Cannot get TM factory - retrying...");
240: try {
241: Thread.sleep(2000 * (i + 1));
242: } catch (InterruptedException e2) {
243: throw new ServiceException(
244: "Cannot get TM factory", e2);
245: }
246: } else {
247: logger.log(BasicLevel.ERROR,
248: "TransactionService: Cannot get TM factory:\n"
249: + e);
250: throw new ServiceException(
251: "TransactionService: Cannot get TM factory",
252: e);
253: }
254: }
255: }
256: }
257:
258: // Create and init the unique Current object.
259: // Current is the local TransactionManager. It must be present in every
260: // jonas server and implements the JTA TransactionManager interface.
261: //
262: // In case of a JTM standalone:
263: // We must create the current only to export it via JNDI for clients
264: // that want to get UserTransaction.
265: current = new Current(tm);
266: setTimeout(timeout);
267:
268: try {
269: if (mbeanServer != null) {
270: // Register TransactionService MBean : only used by jo,nasAdmin's tree builder
271: mbeanServer.registerMBean(this , JonasObjectName
272: .transactionService());
273:
274: // JTAResource implemented by this Service
275: // ------------------------------------------------
276: try {
277: String sJTAResourceName = "JTAResource";
278: ObjectName onJTAResource = J2eeObjectName
279: .JTAResource(getDomainName(),
280: getJonasServerName(),
281: sJTAResourceName);
282: JTAResource jtaResourceMBean = new JTAResource(
283: onJTAResource.toString(), this ,
284: new Integer(timeout),
285: new Boolean(jtmlocal), new Integer(tm
286: .getPortNumber()), tm.getHostName());
287: ManagedBean oManaged = oRegistry
288: .findManagedBean("JTAResource");
289: ModelMBean oMBean = oManaged
290: .createMBean(jtaResourceMBean);
291: if (logger.isLoggable(BasicLevel.DEBUG)) {
292: logger.log(BasicLevel.DEBUG,
293: "JTAResource J2EEResource created");
294: }
295: mbeanServer.registerMBean(oMBean, onJTAResource);
296: } catch (Exception e) {
297: e.printStackTrace();
298: logger.log(BasicLevel.ERROR,
299: "JOnAS: Cannot register JTAResource mBean"
300: + e);
301: }
302: }
303: } catch (ServiceException se) {
304: // Jmx Service not available, do nothing
305: } catch (Exception e) {
306: logger.log(BasicLevel.ERROR,
307: "TransactionService: Cannot start the Transaction service:\n"
308: + e);
309: throw new ServiceException(
310: "TransactionService: Cannot start the Transaction service",
311: e);
312: }
313:
314: if (logger.isLoggable(BasicLevel.DEBUG)) {
315: logger.log(BasicLevel.DEBUG,
316: "TransactionService started, default timeout= "
317: + timeout);
318: }
319:
320: }
321:
322: /**
323: * Stop the transaction service
324: * Not already implementated
325: * @throws ServiceException if the service stop fails
326: */
327: public void doStop() throws ServiceException {
328: if (logger.isLoggable(BasicLevel.DEBUG)) {
329: logger
330: .log(BasicLevel.DEBUG,
331: "Stop of TransactionService not already implemented");
332: }
333: }
334:
335: // -------------------------------------------------------------------
336: // TransactionService Implementation
337: // -------------------------------------------------------------------
338:
339: /**
340: * Gets the Current object instance
341: * @return the current object
342: */
343: public Current getCurrent() {
344: return current;
345: }
346:
347: /**
348: * Gets the TransactionManager object instance
349: * @return the transaction manager
350: */
351: public TransactionManager getTransactionManager() {
352: return (TransactionManager) current;
353: }
354:
355: /**
356: * Gets the UserTransaction object instance
357: * @return the user transaction object
358: */
359: public UserTransaction getUserTransaction() {
360: return (UserTransaction) current;
361: }
362:
363: /**
364: * Gets the TransactionFactory object (JTM factory)
365: * @return the transaction factory (JTM object)
366: */
367: public TransactionFactory getTransactionFactory() {
368: return tm;
369: }
370:
371: public int getTimeout() {
372: return current.getDefaultTimeout();
373: }
374:
375: /**
376: * Sets the default transaction timeout and register Current in JNDI
377: * @param t new value for time-out
378: */
379: public void setTimeout(int t) {
380:
381: if (logger.isLoggable(BasicLevel.DEBUG)) {
382: logger.log(BasicLevel.DEBUG, "" + t);
383: }
384: current.setDefaultTimeout(t);
385:
386: // Register a UserTransactionFactory in JNDI.
387: // Only if we are inside the JTM
388: if (jtmlocal) {
389: try {
390: if (logger.isLoggable(BasicLevel.DEBUG)) {
391: logger.log(BasicLevel.DEBUG,
392: "Register UserTransactionFactory");
393: }
394: NamingManager.getInstance().getInitialContext().rebind(
395: "javax.transaction.UserTransaction", current);
396: } catch (NamingException e) {
397: logger.log(BasicLevel.ERROR,
398: "Cannot rebind UserTransaction:" + e);
399: }
400: }
401:
402: }
403:
404: /**
405: * Get begun transactions number
406: * @return total number of begun transactions
407: */
408: protected int getTotalBegunTransactions() {
409: return current.getTotalBegunTransactions();
410: }
411:
412: /**
413: * Get committed transactions number
414: * @return total number of committed transactions
415: */
416: protected int getTotalCommittedTransactions() {
417: return current.getTotalCommittedTransactions();
418: }
419:
420: /**
421: * Get current transactions number
422: * @return total number of current transactions
423: */
424: protected int getTotalCurrentTransactions() {
425: return current.getTotalCurrentTransactions();
426: }
427:
428: /**
429: * Get expired transactions number
430: * @return total number of expired transactions
431: */
432: protected int getTotalExpiredTransactions() {
433: return current.getTotalExpiredTransactions();
434: }
435:
436: /**
437: * Get rollebacked transactions number
438: * @return total number of rollbacked transactions
439: */
440: protected int getTotalRolledbackTransactions() {
441: return current.getTotalRolledbackTransactions();
442: }
443:
444: /**
445: * Reset all transaction counters
446: */
447: protected void resetAllTxTotalCounters() {
448: current.resetAllTxTotalCounters();
449: }
450:
451: /**
452: * Get all currently executing Xids
453: * @return total number of executing Xids
454: */
455: protected Xid[] getAllActiveXids() {
456: return (current.getAllXid());
457: }
458:
459: /**
460: * Get all currently executing transactions
461: * @return total number of executing transaction
462: */
463: protected String[] getAllActiveTx() {
464: String[] mysArray;
465:
466: mysArray = current.getAllTx();
467: return mysArray;
468: }
469:
470: /**
471: * Get all transactions that require administrator recovery action
472: * @return Transactions that require administrator recovery action
473: */
474: protected String[] getAllRecoveryTx() {
475: String[] mysArray;
476:
477: mysArray = current.getAllRcTx();
478: return mysArray;
479: }
480:
481: /**
482: * Get all XAResoures of a transaction that require administrator recovery action
483: * @return XAResources that require administrator recovery action
484: */
485: protected String[] getAllXAResource(String xtx) {
486: String[] mysArray;
487:
488: mysArray = current.getAllXaTx(xtx);
489: return mysArray;
490: }
491:
492: /**
493: * @return Returns all XAResources that require administrator recovery action.
494: */
495: protected int commitXAResource(String xatx) {
496: int commiterror;
497: commiterror = current.actionXAResource("commit", xatx);
498: return commiterror;
499: }
500:
501: /**
502: * @return Returns all XAResources that require administrator recovery action.
503: */
504: protected int rollbackXAResource(String xatx) {
505: int rollbackerror;
506: rollbackerror = current.actionXAResource("rollback", xatx);
507: return rollbackerror;
508: }
509:
510: /**
511: * @return Returns all XAResources that require administrator recovery action.
512: */
513: protected int forgetXAResource(String xatx) {
514: int forgeterror;
515: forgeterror = current.actionXAResource("forget", xatx);
516: return forgeterror;
517: }
518: }
|