/** * */ package org.rhq.plugins.mobicents.servlet.sip; import java.io.File; import java.lang.reflect.Field; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.management.ObjectName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.mc4j.ems.connection.EmsConnection; import org.mc4j.ems.connection.bean.EmsBean; import org.mc4j.ems.connection.bean.operation.EmsOperation; import org.rhq.plugins.jbossas.util.WarDeploymentInformation; import org.rhq.plugins.jmx.ObjectNameQueryUtility; /** * Accesses the MainDeployer mbean to find the deployment files behind services. * * Original file copied over from jopr jboss as plugin trunk rev 26. * getVHosts method has been modified to fetch SipManager instead of Manager * * @author Greg Hinkle * @author <A HREF="mailto:jean.deruelle@gmail.com">Jean Deruelle</A> */ public class ConvergedDeploymentUtility { private static Log log = LogFactory.getLog(ConvergedDeploymentUtility.class); /** * The object name of the JBoss main deployer MBean. */ protected static final String MAIN_DEPLOYER = "jboss.system:service=MainDeployer"; /** * The name of the main deployer operation that is to be used to get the list of the modules are deployed - this is * the Main Deployer operation name for JBossAS 4.x. */ private static final String LIST_DEPLOYED_MODULES_OP_NAME = "listDeployedModules"; /** * The name of the main deployer operation that is to be used to get the list of the modules are deployed - this is * the Main Deployer operation name for JBossAS 3.x. */ private static final String LIST_DEPLOYED_OP_NAME = "listDeployed"; /** * Retrieves all the discovery information for a War resources. We are retrieving all the information * so that there is only ever one call to the MBeanServer to get the deployed mbeans, therefore saving * some performance if it did this for each and every war resource one at a time. * * @param connection EmsConnection to get the mbean information * @param objectNames Name of the main jboss.management mbeans for a collection of wars. * @return map holds all the war deployment information for the objects passed in the objectNames collection */ public static Map<String, List<WarDeploymentInformation>> getConvergedWarDeploymentInformation(EmsConnection connection, List<String> objectNames) { // We need a list of informations, as one jsr77 deployment can end up in multiple web apps in different vhosts HashMap<String, List<WarDeploymentInformation>> retDeploymentInformationMap = new HashMap<String, List<WarDeploymentInformation>>(); // will contain information on all deployments Collection deployed; try { deployed = getDeploymentInformations(connection); } catch (Exception e) { return null; } String separator = System.getProperty("file.separator"); boolean isOnWin = separator.equals("\\"); // Loop through the deployments, get the name information and compare it to the collection // of strings passed into this method // Interpreter i = new Interpreter(); for (Object sdi : deployed) { try { ObjectName jbossWebObjectName = getFieldValue(sdi, "deployedObject", javax.management.ObjectName.class); if (jbossWebObjectName != null) { String shortName = getFieldValue(sdi, "shortName", String.class); for (String objectNameString : objectNames) { String nameFromObject = getMBeanNameAttribute(objectNameString); if (shortName.equals(nameFromObject)) { String jbossWebmBeanName = jbossWebObjectName.getCanonicalName(); String contextRoot = getMBeanNameAttribute(jbossWebmBeanName); int lastSlashIndex = contextRoot.lastIndexOf("/"); if (lastSlashIndex > 0) { int lastIndex = contextRoot.length() - 1; // If it ends in a slash, it's the root context (context root -> "/"). Otherwise, the // context root will be everything after the last slash (e.g. "jmx-console"). contextRoot = (lastSlashIndex == lastIndex) ? "/" : contextRoot.substring(lastSlashIndex + 1); } String file = getFieldValue(sdi, "url", URL.class).toString(); if (file.startsWith("file:/")) { if (isOnWin) { file = file.substring(6); // listDeployed() always delivers / as path separator, so we need to correct this. File tmp = new File(file); file = tmp.getCanonicalPath(); } else file = file.substring(5); } /* * We now have a valid deployment. Go back to the MBeanServer and get *all* * applicable virtual hosts for this web app. Return deployment info for all * of them. * Most of the time this will only be one virtual host called 'localhost', as * this is the default if no vhost is set. */ List<EmsBean> vhosts = getVHosts(contextRoot, connection); List<WarDeploymentInformation> infos = new ArrayList<WarDeploymentInformation>(vhosts .size()); for (EmsBean vhost : vhosts) { WarDeploymentInformation deploymentInformation = new WarDeploymentInformation(); String vhostname = vhost.getBeanName().getKeyProperty("host"); deploymentInformation.setVHost(vhostname); deploymentInformation.setFileName(file); deploymentInformation.setContextRoot(contextRoot); // jboss.web:J2EEApplication=none,J2EEServer=none,j2eeType=WebModule,name=//bsd.de/test // TODO to we have a better tool to exchange a value of a key-value pair in an ObjectName ? int index = jbossWebmBeanName.indexOf("name="); jbossWebmBeanName = jbossWebmBeanName.substring(0, index + 5); jbossWebmBeanName += "//" + vhostname +ConvergedWarDiscoveryHelper.getContextPath(contextRoot); deploymentInformation.setJbossWebModuleMBeanObjectName(jbossWebmBeanName); infos.add(deploymentInformation); } retDeploymentInformationMap.put(objectNameString, infos); } } } } catch (Exception evalError) { log.warn("Failed to determine if a deployment contains our mbean", evalError); } } return retDeploymentInformationMap; } /** * Retrieves the virtual host MBeans for the webapp with the specified context root. * VHost MBeans have the pattern "jboss.web:host=*,path=/<ctx_root>,type=Manager". * * @param contextRoot the context root * * @return the list of VHost MBeans for this webapp */ public static List<EmsBean> getVHosts(String contextRoot, EmsConnection emsConnection) { String pattern = "jboss.web:host=%host%,path=" + ConvergedWarDiscoveryHelper.getContextPath(contextRoot) + ",type=SipManager"; ObjectNameQueryUtility queryUtil = new ObjectNameQueryUtility(pattern); List<EmsBean> mBeans = emsConnection.queryBeans(queryUtil.getTranslatedQuery()); return mBeans; } private static Collection getDeploymentInformations(EmsConnection connection) throws Exception { Collection deploymentInfos = null; EmsOperation operation = null; try { operation = getListDeployedOperation(connection); if (operation == null) { throw new UnsupportedOperationException( "This JBossAS instance is unsupported; its MainDeployer MBean doesn't have a listDeployedModules or listDeployed operation."); } deploymentInfos = (Collection) operation.invoke(new Object[0]); } catch (RuntimeException re) { // Make a last ditch effort in case the call to listDeployedModules() failed due to // https://jira.jboss.org/jira/browse/JBAS-5983. if (operation != null && operation.getName().equals(LIST_DEPLOYED_MODULES_OP_NAME)) { EmsBean mainDeployerMBean = connection.getBean(MAIN_DEPLOYER); operation = mainDeployerMBean.getOperation(LIST_DEPLOYED_OP_NAME); try { deploymentInfos = (Collection) operation.invoke(new Object[0]); } catch (RuntimeException re2) { deploymentInfos = null; } } if (deploymentInfos == null) { log.warn("Cannot determine deployed modules - cause: " + re); throw new Exception(re); } } return deploymentInfos; } private static String getMBeanNameAttribute(String objectBeanName) { Object[] splitName = objectBeanName.split("name="); String retNameAttribute = ""; if (splitName.length > 1) { String afterName = (String) splitName[1]; String[] removeAnythingAfter = afterName.split(","); if (removeAnythingAfter.length > 0) { retNameAttribute = removeAnythingAfter[0]; } else { retNameAttribute = afterName; } } return retNameAttribute; } private static <T> T getFieldValue(Object target, String name, Class<T> T) { if (target == null) return null; Field field; T ret; try { field = target.getClass().getField(name); ret = (T) field.get(target); if (T == ObjectName.class && ret != null) { ret = (T) new ObjectName(ret.toString()); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); return null; } return ret; } protected static EmsOperation getListDeployedOperation(EmsConnection connection) { EmsOperation retOperation; EmsBean bean = connection.getBean(MAIN_DEPLOYER); // first try the new operation name, used by JBossAS 3.2.8 and 4.x. retOperation = bean.getOperation(LIST_DEPLOYED_MODULES_OP_NAME); // if that doesn't exist, we are probably connected to a JBossAS 3.2.7 or earlier version if (retOperation == null) { retOperation = bean.getOperation(LIST_DEPLOYED_OP_NAME); } // if we still did not manage to find the operation name, let the caller handle this error condition return retOperation; } }