/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/**
* PROPRIETARY/CONFIDENTIAL. Use of this product is subject to license terms.
*
* Copyright 2001-2002 by iPlanet/Sun Microsystems, Inc.,
* 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
* All rights reserved.
* $Id: JTSMonitorMBean.java,v 1.6 2007/05/05 05:35:58 tcfujii Exp $
*/
package com.sun.enterprise.transaction.monitor;
import java.util.Map;
import java.util.Hashtable;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.AttributeNotFoundException;
import javax.management.RuntimeOperationsException;
import javax.management.DynamicMBean;
import javax.management.InvalidAttributeValueException;
import javax.management.MBeanException;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.ReflectionException;
import javax.transaction.Transaction;
import javax.transaction.SystemException;
import com.sun.enterprise.admin.monitor.BaseMonitorMBean;
import com.sun.enterprise.admin.monitor.MonitoredObjectType;
import com.sun.enterprise.admin.monitor.types.Counter;
import com.sun.enterprise.admin.monitor.types.MonitoredAttributeType;
import com.sun.enterprise.admin.monitor.types.StringMonitoredAttributeType;
import com.sun.enterprise.J2EETransactionManager;
import com.sun.enterprise.Switch;
import com.sun.enterprise.transaction.TransactionAdminBean;
import com.sun.enterprise.resource.ResourceInstaller;
import java.util.logging.Logger;
import java.util.logging.Level;
import com.sun.logging.LogDomains;
import com.sun.enterprise.util.i18n.StringManager;
//jsr 77 support
import com.sun.enterprise.server.ApplicationServer;
import com.sun.enterprise.server.ServerContext;
import com.sun.enterprise.admin.monitor.registry.*;
import com.sun.enterprise.config.ConfigContext;
import com.sun.enterprise.config.ConfigBean;
import com.sun.enterprise.config.serverbeans.ServerBeansFactory;
import com.sun.enterprise.config.serverbeans.Config;
import com.sun.enterprise.config.ConfigException;
import com.sun.enterprise.config.serverbeans.TransactionService;
import com.sun.enterprise.config.serverbeans.ElementProperty;
/**
* MBean implementation to monitor Transaction Manager.
*/
public class JTSMonitorMBean extends BaseMonitorMBean {
static final String NUM_TRANSACTIONS_COMPLETED = "total-tx-completed";
static final String NUM_TRANSACTIONS_ROLLEDBACK = "total-tx-rolled-back";
static final String NUM_TRANSACTIONS_INFLIGHT = "total-tx-inflight";
static final String IS_FROZEN = "isFrozen";
static final String INFLIGHT_TRANSACTIONS = "inflight-tx";
static final String ROLLBACK = "rollbackList";
static final String FREEZE = "freeze";
static final int COLUMN_LENGTH = 25;
public static final String TRANSACTION_ID = "TransactionId";
public static final String STATE = "TransactionState";
public static final String ELAPSED_TIME = "ElapsedTime";
public static final String COMPONENT_NAME = "ComponentName";
public static final String RESOURCE_NAMES = "ResourceNames";
// Sting Manager for Localization
private static StringManager sm = StringManager.getManager(JTSMonitorMBean.class);
/**
Logger to log transaction messages
*/
static Logger _logger = LogDomains.getLogger(LogDomains.JTA_LOGGER);
/**
* A 2-d array initialized to attribute names and their types
*/
private static Object[][] attrNameTypeArray = {
{NUM_TRANSACTIONS_COMPLETED, Counter.INTEGER},
{NUM_TRANSACTIONS_ROLLEDBACK, Counter.INTEGER},
{NUM_TRANSACTIONS_INFLIGHT, Counter.INTEGER},
{IS_FROZEN, StringMonitoredAttributeType.DEFAULT},
{INFLIGHT_TRANSACTIONS, StringMonitoredAttributeType.DEFAULT}
};
private static MBeanOperationInfo[] operationInfoArray =
new MBeanOperationInfo[2];
/**
* JTSAdminClient to get the monitor data from, and to invoke user actions
*/
private J2EETransactionManager txnMgr;
private Hashtable txnTable = null;
private MonitoredObjectType type = MonitoredObjectType.TXNMGR;
private boolean monitorOn = false;
private long startTime = 0;
/**
* Map of attribute names and their types
*/
private static Map attrNameTypeMap;
/**
* Info on this MBean
*/
private static MBeanInfo mBeanInfo;
static {
attrNameTypeMap = createAttrNameTypeMap(attrNameTypeArray);
operationInfoArray[0] = new MBeanOperationInfo(ROLLBACK,
"rollback(String txnId): Marks the transaction for rollback",
null, "void", MBeanOperationInfo.ACTION);
operationInfoArray[1] = new MBeanOperationInfo(FREEZE,
"freeze(): Freezes the transactions",
null, "void", MBeanOperationInfo.ACTION);
mBeanInfo = createMBeanInfo(attrNameTypeMap, operationInfoArray);
}
/**
* Creates a new instance of JTSMonitorMBean
*/
public JTSMonitorMBean() {
txnMgr = Switch.getSwitch().getTransactionManager();
ServerContext sCtx = ApplicationServer.getServerContext();
if (sCtx != null) {
try {
ConfigContext ctx = sCtx.getConfigContext();
Config cfg = ServerBeansFactory.getConfigBean(ctx);
String lvl = cfg.getMonitoringService().getModuleMonitoringLevels().getTransactionService();
MonitoringLevel l = MonitoringLevel.instance(lvl);
if (l != MonitoringLevel.OFF) {
startMonitoring();
}
MonitoringRegistry registry = sCtx.getMonitoringRegistry();
JTAStatsImpl.createInstance(this);
JTAStatsImpl statImpl = JTAStatsImpl.getInstance();
registry.registerJTAStats(statImpl, statImpl);
_logger.log(Level.FINE,"JTAStats monitoring registration completed");
TransactionService txnService = ServerBeansFactory.getTransactionServiceBean(ctx);
ElementProperty[] eprops = txnService.getElementProperty();
for (int index = 0; index < eprops.length; index++) {
if ("pending-txn-cleanup-interval".equals(eprops[index].getName())) {
int interval = 60;
if (eprops[index].getValue() != null)
interval = Integer.parseInt(eprops[index].getValue());
new RecoveryHelperThread(interval).start();
if (_logger.isLoggable(Level.FINE))
_logger.log(Level.FINE,"Asynchronous thread for incomplete tx is enabled with interval " + interval);
}
}
} catch (MonitoringRegistrationException mex) {
_logger.log(Level.WARNING,"transaction.monitor.registration_failed", mex);
} catch (ConfigException e) {
_logger.log(Level.WARNING,"transaction.monitor.registration_failed", e);
}
}
else {
_logger.log(Level.FINE,"JTSMonitorMBean: ServerContext is null: monitoring is not enabled");
}
}
public List<Map<String, String>> listActiveTransactions() {
ArrayList aList = txnMgr.getActiveTransactions();
if (aList.isEmpty())
return new ArrayList<Map<String, String>>(0);
txnTable = new Hashtable();
List<Map<String, String>> activeTxnList = new ArrayList<Map<String, String>>();
Map<String, String> txnListEntry = null;
for (int i=0; i < aList.size(); i++) {
TransactionAdminBean txnBean = (TransactionAdminBean)aList.get(i);
Transaction j2eeTxn = (Transaction) txnBean.getIdentifier();
String txnId = txnBean.getId();
txnTable.put(txnId, j2eeTxn);
txnListEntry = new HashMap<String, String>(5);
txnListEntry.put(TRANSACTION_ID, txnId);
txnListEntry.put(ELAPSED_TIME, String.valueOf(txnBean.getElapsedTime()));
txnListEntry.put(COMPONENT_NAME, txnBean.getComponentName());
ArrayList<String> resourceList = txnBean.getResourceNames();
StringBuffer strBuf = new StringBuffer(" ");
if (resourceList != null) {
for (int k = 0; k < resourceList.size(); k++) {
strBuf.append(resourceList.get(k));
strBuf.append(",");
}
}
txnListEntry.put(RESOURCE_NAMES, strBuf.toString());
txnListEntry.put(STATE, txnBean.getStatus());
activeTxnList.add(txnListEntry);
}
return activeTxnList;
}
/**
* Obtains the value of a specific monitored attribute.
* @param attribute The name of the attribute to be retrieved
* @return The value of the attribute retrieved.
* @throws AttributeNotFoundException if attribute name is not valid
*/
public Object getAttribute(String attribute) throws AttributeNotFoundException{
if (attribute == null) {
/**
throw new RuntimeOperationsException(
new IllegalArgumentException("Attribute name cannot be null"));
**/
throw new RuntimeOperationsException(
new IllegalArgumentException(sm.getString("transaction.monitor.attribute_is_null")));
}
// Call the corresponding getter for a recognized attribute_name
if (attribute.equals(NUM_TRANSACTIONS_COMPLETED)) {
return new Integer(txnMgr.getNumberOfTransactionsCommitted());
}
if (attribute.equals(NUM_TRANSACTIONS_ROLLEDBACK)) {
return new Integer(txnMgr.getNumberOfTransactionsRolledBack());
}
if (attribute.equals(NUM_TRANSACTIONS_INFLIGHT)) {
return new Integer(txnMgr.getNumberOfActiveTransactions());
}
if (attribute.equals(IS_FROZEN)) {
if (txnMgr.isFrozen())
return "True";
else
return "False";
}
if (attribute.equals(INFLIGHT_TRANSACTIONS)) {
ArrayList aList = txnMgr.getActiveTransactions();
// if (aList.isEmpty()) return "No active transaction found.";
if (aList.isEmpty()) return "";
StringBuffer strBuf = new StringBuffer(1024);
txnTable = new Hashtable();
//Set the headings for the tabular output
if (aList.size() > 0) {
String colName = "Transaction Id";
strBuf.append("\n\n");
strBuf.append(colName);
for (int i=colName.length(); i<COLUMN_LENGTH+15; i++){
strBuf.append(" ");
}
colName = "Status";
strBuf.append(colName);
for (int i=colName.length(); i<COLUMN_LENGTH; i++){
strBuf.append(" ");
}
colName = "ElapsedTime(ms)";
strBuf.append(colName);
for (int i=colName.length(); i<COLUMN_LENGTH; i++){
strBuf.append(" ");
}
colName = "ComponentName";
strBuf.append(colName);
for (int i=colName.length(); i<COLUMN_LENGTH; i++){
strBuf.append(" ");
}
strBuf.append("ResourceNames\n");
}
for (int i=0; i < aList.size(); i++) {
TransactionAdminBean txnBean = (TransactionAdminBean)aList.get(i);
Transaction j2eeTxn = (Transaction) txnBean.getIdentifier();
String txnId = txnBean.getId();
txnTable.put(txnId, j2eeTxn);
strBuf.append("\n");
strBuf.append(txnId);
for (int j=txnId.length(); j<COLUMN_LENGTH+15; j++){
strBuf.append(" ");
}
strBuf.append(txnBean.getStatus());
for (int j=txnBean.getStatus().length(); j<COLUMN_LENGTH; j++){
strBuf.append(" ");
}
strBuf.append(String.valueOf(txnBean.getElapsedTime()));
for (int j=(String.valueOf(txnBean.getElapsedTime()).length()); j<COLUMN_LENGTH; j++){
strBuf.append(" ");
}
strBuf.append(txnBean.getComponentName());
for (int j=txnBean.getComponentName().length(); j<COLUMN_LENGTH; j++){
strBuf.append(" ");
}
ArrayList<String> resourceList = txnBean.getResourceNames();
if (resourceList != null) {
for (int k = 0; k < resourceList.size(); k++) {
strBuf.append(resourceList.get(k));
strBuf.append(",");
}
}
}
return strBuf.toString();
}
// If attribute_name has not been recognized
// throw(new AttributeNotFoundException("Cannot find " + attribute + " attribute" ));
throw(new AttributeNotFoundException(sm.getString("transaction.monitor.attribute_not_found",attribute ) ));
}
/**
* Get the values of several attributes of the monitoring MBean.
* @param attributes A list of the attributes to be retrieved.
* @return The list of attributes retrieved.
*/
public AttributeList getAttributes(String[] attributeNames) {
// Check attributeNames to avoid NullPointerException later on
if (attributeNames == null) {
/**
throw new RuntimeOperationsException(
new IllegalArgumentException(
"attributeNames[] cannot be null"));
**/
throw new RuntimeOperationsException(
new IllegalArgumentException(
sm.getString("transaction.monitor.attributes_not_null")));
}
AttributeList resultList = new AttributeList();
// if attributeNames is empty, return an empty result list
if (attributeNames.length == 0)
return resultList;
// build the result attribute list
for (int i=0 ; i<attributeNames.length ; i++){
try {
Object value = getAttribute((String) attributeNames[i]);
resultList.add(new Attribute(attributeNames[i],value));
} catch (Exception e) {
// print debug info but continue processing list
_logger.log(Level.WARNING,"transaction.monitor.error_while_getting_monitor_attr",e);
}
}
return(resultList);
}
public Object invoke(String operationName, Object[] params, String[] signature) throws MBeanException, ReflectionException {
if (operationName == null || operationName.equals("")) {
/**
throw new RuntimeOperationsException(
new IllegalArgumentException("operationName cannot be null"));
**/
throw new RuntimeOperationsException(
new IllegalArgumentException(sm.getString("transaction.monitor.operation_name_is_null")));
}
if (params == null)
return null;
AttributeList resultList = new AttributeList();
if (operationName.equals(ROLLBACK)) {
for (int i=0; i<params.length; i++) {
String txnId = (String) params[i];
Object value = setRollback(txnId);
resultList.add(new Attribute(txnId, value));
}
} else if (operationName.equals(FREEZE)) {
if (params[0].equals("true")) {
txnMgr.freeze();
resultList.add(new Attribute("freeze", "Successful"));
} else {
txnMgr.unfreeze();
resultList.add(new Attribute("unfreeze", "Successful"));
}
} else {
throw new UnsupportedOperationException(UNSUPPORTED_ERRMSG);
}
return resultList;
}
public void freeze() {
txnMgr.freeze();
}
public void unfreeze() {
txnMgr.unfreeze();
}
public String[] rollback(String[] txnIds) {
if (txnIds == null || txnIds.length == 0)
return new String[0];
String result[] = new String[txnIds.length];
for (int i = 0; i < txnIds.length; i++) {
result[i] = (String) setRollback(txnIds[i]);
}
return result;
}
public Object setRollback(String txnId) throws IllegalStateException {
// Lookup the transaction Array for the txnid
String result = "";
if (txnTable == null || txnTable.get(txnId) == null) {
result = sm.getString("transaction.monitor.rollback_invalid_id");
throw new IllegalStateException(result);
}
else {
// Call the TransactionManager to rollback
try {
txnMgr.forceRollback((Transaction)txnTable.get(txnId));
result = sm.getString("transaction.monitor.rollback_sucessful");
} catch (IllegalStateException e) {
// current thread is not associated with the transaction
result = sm.getString("transaction.monitor.rollback_unsuccessful_not_associated");
IllegalStateException ex = new IllegalStateException(result);
ex.initCause(e);
throw ex;
} catch (SecurityException e) {
// Thread is not allowed to rollback the transaction
result = sm.getString("transaction.monitor.rollback_unsuccessful_security_exception");
SecurityException ex = new SecurityException(result);
ex.initCause(e);
throw ex;
} catch (SystemException e) {
// Transaction Manager encountered unexpected error condition
result = sm.getString("transaction.monitor.rollback_unsuccessful_unexpected_exception");
IllegalStateException ex = new IllegalStateException(result);
ex.initCause(e);
throw ex;
}
}
return result;
}
/**
* Start monitoring on this component. This will be called when monitoring
* is enabled on this component (or the group containing this component)
* through user interface.
* @see stopMonitoring
*/
public void startMonitoring() {
txnMgr.setMonitoringEnabled(true);
monitorOn = true;
startTime = System.currentTimeMillis();
}
/**
* Stop monitoring on this component. Called when monitoring is disabled on
* user interface.
*/
public void stopMonitoring() {
txnMgr.setMonitoringEnabled(false);
monitorOn = false;
startTime = 0;
}
public long getStartTime() {
return startTime;
}
/**
* Provides the exposed attributes and actions of the monitoring MBean using
* an MBeanInfo object.
* @return An instance of MBeanInfo with all attributes and actions exposed
* by this monitoring MBean.
*/
public MBeanInfo getMBeanInfo() {
return mBeanInfo;
}
/**
* Get a map of monitored attribute names and their types. The keys in
* the map are names of the attribute and the values are their types. The
* type value are instances of class
* com.iplanet.ias.monitor.type.MonitoredAttributeType (or its sub-classes)
*
* @return map of names and types of all monitored attributes
*/
public Map getMonitoringMetaData() {
return attrNameTypeMap;
}
/**
* Get type of the specified monitored attribute.
*/
public MonitoredAttributeType getAttributeType(String attrName) {
MonitoredAttributeType type = null;
if (attrNameTypeMap != null && attrName != null) {
type = (MonitoredAttributeType)attrNameTypeMap.get(attrName);
}
return type;
}
public MonitoredObjectType getMonitoredObjectType() {
return type;
}
public static void recover(boolean delegated, String txLogDir) throws Exception {
ResourceInstaller resInstaller = Switch.getSwitch().getResourceInstaller();
boolean result = true;
if (resInstaller == null) {
throw new IllegalStateException();
}
if (!delegated) { // own recovery
result = resInstaller.recoverIncompleteTx(false, null);
}
else { // delegated recovery
result = resInstaller.recoverIncompleteTx(true, txLogDir);
}
if (!result)
throw new IllegalStateException();
}
class RecoveryHelperThread extends Thread {
private int interval;
RecoveryHelperThread(int interval) {
setName("Recovery Helper Thread");
setDaemon(true);
this.interval = interval;
}
public void run() {
try {
while(true) {
Thread.sleep(interval*1000);
Switch.getSwitch().getResourceInstaller().recoverIncompleteTx(false, null);
}
} catch (Exception ex) {
if (JTSMonitorMBean._logger.isLoggable(Level.FINE))
JTSMonitorMBean._logger.log(Level.FINE, " Exception occurred in recoverInCompleteTx ");
}
}
}
}
|