/*
* 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.
*/
/*
* $Id: JMSDestination.java,v 1.18 2007/05/05 05:24:09 tcfujii Exp $
* author sreenivas.munnangi@sun.com
*/
package com.sun.enterprise.admin.mbeans;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.management.Attribute;
import javax.management.AttributeList;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import com.sun.enterprise.admin.common.JMSDestinationInfo;
import com.sun.enterprise.admin.common.constant.AdminConstants;
import com.sun.enterprise.admin.common.constant.JMSAdminConstants;
import com.sun.enterprise.admin.common.exception.JMSAdminException;
import com.sun.enterprise.admin.target.Target;
import com.sun.enterprise.admin.target.TargetType;
import com.sun.enterprise.connectors.ConnectorRuntime;
import com.sun.enterprise.connectors.system.MQJMXConnectorInfo;
import com.sun.enterprise.connectors.system.ActiveJmsResourceAdapter;
import com.sun.enterprise.util.i18n.StringManager;
import com.sun.messaging.jms.management.server.DestinationType;
import com.sun.messaging.jms.management.server.MQObjectName;
/**
* A helper class used for performing MQ related administration
* operations using MQ's JMX API.
*
* @author Sreenivas Munnangi
* @author Sivakumar Thyagarajan
* @since SJSAS9.0
*/
public class JMSDestination {
// flag to enable the use of JMX for JMS destination commands
// if false uses the old behavior
// The value for DONT_USE_MQ_JMX can be set thru sysproperty
private static final boolean USE_JMX =
!(Boolean.getBoolean("DONT_USE_MQ_JMX"));
private static final Logger sLogger =
Logger.getLogger(AdminConstants.kLoggerName);
private static final StringManager localStrings =
StringManager.getManager( JMSDestination.class);
// default constructor
public JMSDestination () {
}
// create-jmsdest
public void createJMSDestination(String destName, String destType,
Properties destProps, String tgtName) throws JMSAdminException {
sLogger.log(Level.FINE, "createJMSDestination ...");
MQJMXConnectorInfo mqInfo = getMQJMXConnectorInfo(tgtName);
//MBeanServerConnection mbsc = getMBeanServerConnection(tgtName);
try {
MBeanServerConnection mbsc = mqInfo.getMQMBeanServerConnection();
ObjectName on = new ObjectName(
MQObjectName.DESTINATION_MANAGER_CONFIG_MBEAN_NAME);
String [] signature = null;
AttributeList destAttrs = null;
Object [] params = null;
if (destProps != null) {
destAttrs = convertProp2Attrs(destProps);
}
// setAppserverDefaults(destAttrs, mqInfo);
if (destType.equalsIgnoreCase(JMSAdminConstants.JMS_DEST_TYPE_TOPIC)) {
destType = DestinationType.TOPIC;
} else if (destType.equalsIgnoreCase(JMSAdminConstants.JMS_DEST_TYPE_QUEUE)) {
destType = DestinationType.QUEUE;
}
if ((destAttrs == null) || (destAttrs.size() == 0)){
signature = new String [] {
"java.lang.String",
"java.lang.String"};
params = new Object [] {destType, destName};
} else {
signature = new String [] {
"java.lang.String",
"java.lang.String",
"javax.management.AttributeList"};
params = new Object [] {destType, destName, destAttrs};
}
mbsc.invoke(on, "create", params, signature);
} catch (Exception e) {
logAndHandleException(e, "admin.mbeans.rmb.error_creating_jms_dest");
} finally {
try {
if(mqInfo != null) {
mqInfo.closeMQMBeanServerConnection();
}
} catch (Exception e) {
handleException(e);
}
}
}
// delete-jmsdest
public void deleteJMSDestination(String destName, String destType,
String tgtName)
throws JMSAdminException {
sLogger.log(Level.FINE, "deleteJMSDestination ...");
MQJMXConnectorInfo mqInfo = getMQJMXConnectorInfo(tgtName);
//MBeanServerConnection mbsc = getMBeanServerConnection(tgtName);
try {
MBeanServerConnection mbsc = mqInfo.getMQMBeanServerConnection();
ObjectName on = new ObjectName(
MQObjectName.DESTINATION_MANAGER_CONFIG_MBEAN_NAME);
String [] signature = null;
Object [] params = null;
signature = new String [] {
"java.lang.String",
"java.lang.String"};
if (destType.equalsIgnoreCase("topic")) {
destType = DestinationType.TOPIC;
} else if (destType.equalsIgnoreCase("queue")) {
destType = DestinationType.QUEUE;
}
params = new Object [] {destType, destName};
mbsc.invoke(on, "destroy", params, signature);
} catch (Exception e) {
//log JMX Exception trace as WARNING
logAndHandleException(e, "admin.mbeans.rmb.error_deleting_jms_dest");
} finally {
try {
if(mqInfo != null) {
mqInfo.closeMQMBeanServerConnection();
}
} catch (Exception e) {
handleException(e);
}
}
}
// list-jmsdest
public JMSDestinationInfo [] listJMSDestinations(String tgtName, String destType)
throws JMSAdminException {
sLogger.log(Level.FINE, "listJMSDestination ...");
MQJMXConnectorInfo mqInfo = getMQJMXConnectorInfo(tgtName);
//MBeanServerConnection mbsc = getMBeanServerConnection(tgtName);
try {
MBeanServerConnection mbsc = mqInfo.getMQMBeanServerConnection();
ObjectName on = new ObjectName(
MQObjectName.DESTINATION_MANAGER_CONFIG_MBEAN_NAME);
String [] signature = null;
Object [] params = null;
ObjectName [] dests = (ObjectName [])mbsc.invoke(on, "getDestinations", params, signature);
if ((dests != null) && (dests.length > 0)) {
List<JMSDestinationInfo> jmsdi = new ArrayList<JMSDestinationInfo>();
for (int i=0; i<dests.length; i++) {
on = dests[i];
String jdiType = DestinationType.toStringLabel(on.getKeyProperty("desttype"));
String jdiName = on.getKeyProperty("name");
// check if the destination name has double quotes at the beginning
// and end, if yes strip them
if ((jdiName != null) && (jdiName.length() > 1)) {
if (jdiName.indexOf('"') == 0) {
jdiName = jdiName.substring(1);
}
if (jdiName.lastIndexOf('"') == (jdiName.length() - 1)) {
jdiName = jdiName.substring(0, jdiName.lastIndexOf('"'));
}
}
JMSDestinationInfo jdi = new JMSDestinationInfo(jdiName, jdiType);
if(destType == null) {
jmsdi.add(jdi);
} else if (destType.equals(JMSAdminConstants.JMS_DEST_TYPE_TOPIC)
|| destType.equals(JMSAdminConstants.JMS_DEST_TYPE_QUEUE)) {
//Physical Destination Type specific listing
if (jdiType.equalsIgnoreCase(destType)) {
jmsdi.add(jdi);
}
}
}
return (JMSDestinationInfo[]) jmsdi.toArray(new JMSDestinationInfo[]{});
}
} catch (Exception e) {
//log JMX Exception trace as WARNING
logAndHandleException(e, "admin.mbeans.rmb.error_listing_jms_dest");
} finally {
try {
if(mqInfo != null) {
mqInfo.closeMQMBeanServerConnection();
}
} catch (Exception e) {
handleException(e);
}
}
return null;
}
// JMSPing
// String status of jms ping RUNNING or exception
public String JMSPing(String tgtName)
throws JMSAdminException {
sLogger.log(Level.FINE, "JMSPing ...");
MQJMXConnectorInfo mqInfo = null;
try {
MQJMXConnectorInfo [] cInfo =
ConnectorRuntime.getRuntime().getMQJMXConnectorInfo(tgtName);
if ((cInfo == null) || (cInfo.length < 1)) {
throw new JMSAdminException(
localStrings.getString("admin.mbeans.rmb.error_obtaining_jms"));
}
int k = -1;
for (int i=0; i<cInfo.length; i++) {
if (tgtName.equals(cInfo[i].getASInstanceName())) {
k = i;
break;
}
}
if (k == -1) {
throw new JMSAdminException(
localStrings.getString("admin.mbeans.rmb.invalid_server_instance", tgtName));
}
mqInfo = cInfo[k];
MBeanServerConnection mbsc = cInfo[k].getMQMBeanServerConnection();
//perform some work on the connection to check for connection health.
mbsc.getMBeanCount();
} catch (Exception e) {
//log JMX Exception trace as WARNING
logAndHandleException(e, "admin.mbeans.rmb.error_pinging_jms");
} finally {
try {
if(mqInfo != null) {
mqInfo.closeMQMBeanServerConnection();
}
} catch (Exception e) {
handleException(e);
}
}
return JMSAdminConstants.JMS_HOST_RUNNING;
}
// purge-jmsdest
public void purgeJMSDestination(String destName, String destType, String tgtName)
throws JMSAdminException {
sLogger.log(Level.FINE, "purgeJMSDestination ...");
MQJMXConnectorInfo mqInfo = getMQJMXConnectorInfo(tgtName);
//MBeanServerConnection mbsc = getMBeanServerConnection(tgtName);
try {
MBeanServerConnection mbsc = mqInfo.getMQMBeanServerConnection();
if (destType.equalsIgnoreCase("topic")) {
destType = DestinationType.TOPIC;
} else if (destType.equalsIgnoreCase("queue")) {
destType = DestinationType.QUEUE;
}
ObjectName on =
MQObjectName.createDestinationConfig(destType, destName);
String [] signature = null;
Object [] params = null;
mbsc.invoke(on, "purge", params, signature);
} catch (Exception e) {
//log JMX Exception trace as WARNING
logAndHandleException(e, "admin.mbeans.rmb.error_purging_jms_dest");
} finally {
try {
if(mqInfo != null) {
mqInfo.closeMQMBeanServerConnection();
}
} catch (Exception e) {
handleException(e);
}
}
}
private MQJMXConnectorInfo getMQJMXConnectorInfo(String tgtName)
throws JMSAdminException {
sLogger.log(Level.FINE, "getMQJMXConnectorInfo for " + tgtName);
MQJMXConnectorInfo mcInfo = null;
try {
MQJMXConnectorInfo [] cInfo =
ConnectorRuntime.getRuntime().getMQJMXConnectorInfo(tgtName);
if ((cInfo == null) || (cInfo.length < 1)) {
throw new JMSAdminException(
localStrings.getString("admin.mbeans.rmb.error_obtaining_jms"));
}
mcInfo = cInfo[0];
} catch (Exception e) {
handleException(e);
}
return mcInfo;
}
/*
private MBeanServerConnection getMBeanServerConnection(String tgtName)
throws JMSAdminException {
sLogger.log(Level.FINE, "getMBeanServerConnection for " + tgtName);
MBeanServerConnection mbsc = null;
try {
MQJMXConnectorInfo [] cInfo =
ConnectorRuntime.getRuntime().getMQJMXConnectorInfo(tgtName);
if ((cInfo == null) || (cInfo.length < 1)) {
throw new JMSAdminException(
localStrings.getString("admin.mbeans.rmb.error_obtaining_jms"));
}
mbsc = cInfo[0].getMQMBeanServerConnection();
sLogger.log(Level.FINE, "MBeanServerConnection = " + mbsc);
} catch (Exception e) {
handleException(e);
}
return mbsc;
}
*/
private void setAppserverDefaults(AttributeList destAttrs,
MQJMXConnectorInfo info) {
if (destAttrs == null) {
destAttrs = new AttributeList();
}
if (info.getBrokerType().equalsIgnoreCase(ActiveJmsResourceAdapter.LOCAL)) {
String localDelivery = "LocalDeliveryPreferred";
boolean notPresent = true;
for (Object obj : destAttrs) {
Attribute attrib = (Attribute) obj;
if (attrib.getName().equals(localDelivery)) {
notPresent = false;
}
}
if (notPresent) {
Attribute attrib = new Attribute (localDelivery,
Boolean.valueOf("true"));
destAttrs.add(attrib);
}
}
}
//XXX: To refactor into a Generic attribute type mapper, so that it is extensible later.
private AttributeList convertProp2Attrs(Properties destProps) {
AttributeList destAttrs = new AttributeList();
String propName = null;
String propValue = null;
for (Enumeration e = destProps.propertyNames(); e.hasMoreElements();) {
propName = (String) e.nextElement();
if (propName.equals("AutoCreateQueueMaxNumActiveConsumers")) {
destAttrs.add(new Attribute("AutoCreateQueueMaxNumActiveConsumers",
Integer.valueOf(destProps.getProperty("AutoCreateQueueMaxNumActiveConsumers"))));
} else if (propName.equals("maxNumActiveConsumers")) {
destAttrs.add(new Attribute("MaxNumActiveConsumers",
Integer.valueOf(destProps.getProperty("maxNumActiveConsumers"))));
} else if (propName.equals("MaxNumActiveConsumers")) {
destAttrs.add(new Attribute("MaxNumActiveConsumers",
Integer.valueOf(destProps.getProperty("MaxNumActiveConsumers"))));
} else if (propName.equals("AutoCreateQueueMaxNumBackupConsumers")) {
destAttrs.add(new Attribute("AutoCreateQueueMaxNumBackupConsumers",
Integer.valueOf(destProps.getProperty("AutoCreateQueueMaxNumBackupConsumers"))));
} else if (propName.equals("AutoCreateQueues")) {
boolean b = false;
propValue = destProps.getProperty("AutoCreateQueues");
if (propValue.equalsIgnoreCase("true")) {
b = true;
}
destAttrs.add(new Attribute("AutoCreateQueues",
Boolean.valueOf(b)));
} else if (propName.equals("AutoCreateTopics")) {
boolean b = false;
propValue = destProps.getProperty("AutoCreateTopics");
if (propValue.equalsIgnoreCase("true")) {
b = true;
}
destAttrs.add(new Attribute("AutoCreateTopics",
Boolean.valueOf(b)));
} else if (propName.equals("DMQTruncateBody")) {
boolean b = false;
propValue = destProps.getProperty("DMQTruncateBody");
if (propValue.equalsIgnoreCase("true")) {
b = true;
}
destAttrs.add(new Attribute("DMQTruncateBody",
Boolean.valueOf(b)));
} else if (propName.equals("LogDeadMsgs")) {
boolean b = false;
propValue = destProps.getProperty("LogDeadMsgs");
if (propValue.equalsIgnoreCase("true")) {
b = true;
}
destAttrs.add(new Attribute("LogDeadMsgs",
Boolean.valueOf(b)));
} else if (propName.equals("MaxBytesPerMsg")) {
destAttrs.add(new Attribute("MaxBytesPerMsg",
Long.valueOf(destProps.getProperty("MaxBytesPerMsg"))));
} else if (propName.equals("MaxNumMsgs")) {
destAttrs.add(new Attribute("MaxNumMsgs",
Long.valueOf(destProps.getProperty("MaxNumMsgs"))));
} else if (propName.equals("MaxTotalMsgBytes")) {
destAttrs.add(new Attribute("MaxTotalMsgBytes",
Long.valueOf(destProps.getProperty("MaxTotalMsgBytes"))));
} else if (propName.equals("NumDestinations")) {
destAttrs.add(new Attribute("NumDestinations",
Integer.valueOf(destProps.getProperty("NumDestinations"))));
}
}
return destAttrs;
}
/**
* Logs an exception via the logger and throws a JMSAdminException.
*
* This method exists as exceptions that occur while invoke
* MQ JMX operations currently have "nested" exception messages
* and it is very difficult for a user to understand the real
* cause from the exception message. We now throw a generic message
* and log the actual exception in the server log so that users could
* refer to the server log for more information.
*/
private void logAndHandleException(Exception e, String errorMsg)
throws JMSAdminException {
//log JMX Exception trace as WARNING
StringWriter s = new StringWriter();
e.getCause().printStackTrace(new PrintWriter(s));
sLogger.log(Level.WARNING, s.toString());
JMSAdminException je = new JMSAdminException(localStrings.getString(errorMsg));
/* Cause will be InvocationTargetException, cause of that
* wil be MBeanException and cause of that will be the
* real exception we need
*/
if ((e.getCause() != null) &&
(e.getCause().getCause() != null)) {
je.initCause(e.getCause().getCause().getCause());
}
handleException(je);
}
private void handleException(Exception e)
throws JMSAdminException {
if (e instanceof JMSAdminException) {
throw ((JMSAdminException)e);
}
String msg = e.getMessage();
JMSAdminException jae;
if (msg == null) {
jae = new JMSAdminException();
} else {
jae = new JMSAdminException(msg);
}
/*
* Don't do this for now because the CLI does not include jms.jar
* (at least not yet) in the classpath. Sending over a JMSException
* will cause a class not found exception to be thrown.
*/
//jae.setLinkedException(e);
throw jae;
}
/**
* Determines whether MQ JMX connector needs to be used for MQ related
* administrative operations.
*
* @param target Target on which a commands needs to be executed
*/
public static boolean useJMX(Target target) {
/*
if(JMSDestination.USE_JMX) {
if ((target.getType() == TargetType.DAS) || (target.getType() == TargetType.SERVER)) {
return true;
}
}
return false;
*/
return USE_JMX;
}
}
|