// Copyright (c) 2008 James A. Wilson All rights reserved. Use is // subject to license terms. // This file is part of CruiseSaver. // // CruiseSaver is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // CruiseSaver is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with CruiseSaver; if not, write to the Free Software // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA package status; import java.io.IOException; import java.net.MalformedURLException; import java.rmi.UnmarshalException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javax.management.MBeanAttributeInfo; import javax.management.MBeanInfo; import javax.management.MBeanServerConnection; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; import javax.naming.Context; import status.logging.LogUtil; import com.sun.jndi.rmi.registry.RegistryContextFactory; public class BuildStatusJMX implements BuildStatus { private static final Logger logger = LogUtil.getLogger(BuildStatusJMX.class); private final String rmiHost; private final String rmiPort; public BuildStatusJMX() { rmiHost = "localhost"; rmiPort = "1099"; } public BuildStatusJMX(String rmiHost, String rmiPort) { this.rmiHost = rmiHost; this.rmiPort = rmiPort; } /** * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { String server = "localhost"; String port = "1099"; if (args != null && args.length == 2) { server = args[0]; port = args[1]; } BuildStatus build = new BuildStatusJMX(server, port); LogUtil.setDebug(true); // build.getProjects(new String[]{"connectfour"}); for (int i = 0; i < 1; ++i) { build.getProjects(); Thread.sleep(1000); } } /* * (non-Javadoc) * * @see status.BuildStatus#getProjects() */ public List<Project> getProjects() { String[] projectNames = getProjectNames(); return getProjects(projectNames); } /* * (non-Javadoc) * * @see status.BuildStatus#getProjectNames() */ @SuppressWarnings("unchecked") public String[] getProjectNames() { String[] result = new String[0]; MBeanServerConnection connection = getJmxConn(); if (connection == null) { return result; } // using this mbean requires some cruisecontrol source code so I wont ObjectName objName = null; try { objName = new ObjectName("CruiseControl Manager:id=unique"); Object rawAttrib; rawAttrib = connection.getAttribute(objName, "AllProjectsStatus"); Map<String, String> allProjectStatus = (Map<String, String>) rawAttrib; result = new String[allProjectStatus.size()]; result = allProjectStatus.keySet().toArray(result); } catch (Throwable t) { logger.log(Level.SEVERE, "couldn't create controller objectname", t); return result; } dumpMBeanInfo(connection, objName); return result; } private List<Project> getProjects(String[] names) { List<Project> result = new ArrayList<Project>(names.length); MBeanServerConnection connection = getJmxConn(); if (connection == null) { return result; } for (int i = 0; i < names.length; i++) { String projectName = names[i]; Project project = checkBuild(connection, projectName); result.add(project); } return result; } private Project checkBuild(MBeanServerConnection connection, String projectName) { ObjectName mbeanObj; try { mbeanObj = ObjectName.getInstance("CruiseControl Project:name=" + projectName); } catch (MalformedObjectNameException e) { throw new RuntimeException(e); } dumpMBeanInfo(connection, mbeanObj); /* * Status=waiting for next time to build LastBuildSuccessful=true * LogDir=logs/connectfour ProjectName=connectfour * LastBuild=20070120073627 LastSuccessfulBuild=20070120073627 * BuildStartTime= * LabelIncrementer=net.sourceforge.cruisecontrol.labelincrementers * .DefaultLabelIncrementer Label=build.3 BuildInterval=300000 * Paused=false */ Project project = new Project(projectName); try { Object rawAttrib; //LastBuildSuccessful is still in the patch rawAttrib = connection.getAttribute(mbeanObj, "LastBuildSuccessful"); project.setLastBuildSuccesful((Boolean) rawAttrib); rawAttrib = connection.getAttribute(mbeanObj, "BuildInterval"); project.setBuildInterval((Long) rawAttrib); rawAttrib = connection.getAttribute(mbeanObj, "BuildStartTime"); project.setBuildStartTime((String) rawAttrib); rawAttrib = connection.getAttribute(mbeanObj, "LastBuild"); project.setLastBuild((String) rawAttrib); rawAttrib = connection.getAttribute(mbeanObj, "LastSuccessfulBuild"); project.setLastSuccessfulBuild((String) rawAttrib); rawAttrib = connection.getAttribute(mbeanObj, "Status"); project.setStatus((String) rawAttrib); } catch (Throwable e) { logger.log(Level.SEVERE, "error getting attributes.", e); } return project; } private void dumpMBeanInfo(MBeanServerConnection connection, ObjectName mbeanObj) { Level level = Level.FINEST; if (logger.isLoggable(level)) { MBeanInfo beanInfo = null; try { beanInfo = connection.getMBeanInfo(mbeanObj); MBeanAttributeInfo[] attributes = beanInfo.getAttributes(); for (int i = 0; i < attributes.length; i++) { MBeanAttributeInfo attribute = attributes[i]; try { LogUtil.log(logger, level, attribute.getName(), "=", connection .getAttribute(mbeanObj, attribute.getName())); } catch (UnmarshalException e) { LogUtil.log(logger, level, attribute.getName(), "= [UnmarshalException: ", e.getMessage(), "]"); } } } catch (Throwable t) { t.printStackTrace(); } } } private MBeanServerConnection getJmxConn() { // The address of the connector server JMXServiceURL url; String address = "service:jmx:rmi://" + rmiHost + ":" + rmiPort + "/jndi/jrmp"; try { url = new JMXServiceURL(address); } catch (MalformedURLException e) { logger.log(Level.SEVERE, "failed to connect to server: " + address, e); throw new RuntimeException(e.getMessage()); } Map<String, String> environment = new HashMap<String, String>(); environment.put(Context.INITIAL_CONTEXT_FACTORY, RegistryContextFactory.class.getName()); environment.put(Context.PROVIDER_URL, "rmi://" + rmiHost + ":" + rmiPort); // environment.put(Context.SECURITY_PRINCIPAL, "user"); // environment.put(Context.SECURITY_CREDENTIALS, "password"); // Create the JMXCconnectorServer MBeanServerConnection mbeanServerConnection = null; try { JMXConnector cntor = JMXConnectorFactory.connect(url, environment); mbeanServerConnection = cntor.getMBeanServerConnection(); String domain = mbeanServerConnection.getDefaultDomain(); LogUtil.log(logger, Level.FINEST, "found default domain as: ", domain); } catch (IOException e) { logger.log(Level.SEVERE, "connection failed.", e); } return mbeanServerConnection; } @Override public String toString() { return "[BuildStatusJMX: " + rmiHost + ":" + rmiPort + "]"; } }