/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.ant; import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.management.Attribute; import javax.management.MBeanServerConnection; import javax.management.ObjectName; import javax.naming.Context; import javax.naming.InitialContext; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; import org.jboss.util.propertyeditor.PropertyEditors; /** * JMX.java. An ant plugin to call managed operations and set attributes * on mbeans in a jboss jmx mbean server. * To use this plugin with Ant, place the jbossjmx-ant.jar together with the * jboss jars jboss-j2ee.jar and jboss-common-client.jar, and the sun jnet.jar in the * ant/lib directory you wish to use. * If the JMX invoker is secured, set the username and password attributes in the task. * * Here is an example from an ant build file. * * <target name="jmx"> * <taskdef name="jmx" * classname="org.jboss.ant.JMX"/> * <jmx adapterName="jmx:HP.home.home:rmi"> * * <propertyEditor type="java.math.BigDecimal" editor="org.jboss.util.propertyeditor.BigDecimalEditor"/> * <propertyEditor type="java.util.Date" editor="org.jboss.util.propertyeditor.DateEditor"/> * * * <!-- define classes --> * <invoke target="fgm.sysadmin:service=DefineClasses" * operation="defineClasses"> * <parameter type="java.lang.String" arg="defineclasses.xml"/> * </invoke> * </jmx> * * * Created: Tue Jun 11 20:17:44 2002 * * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a> * @author <a href="mailto:dsnyder_lion@users.sourceforge.net">David Snyder</a> * @version */ public class JMX extends Task { private String serverURL; private String adapterName = "jmx/invoker/RMIAdaptor"; private String username; private String password; private List<Operation> ops = new ArrayList<Operation>(); private List<PropertyEditorHolder> editors = new ArrayList<PropertyEditorHolder>(); /** * Creates a new <code>JMX</code> instance. * Provides a default adapterName for the current server, so you only need to set it to * talk to a remote server. * * @exception Exception if an error occurs */ public JMX() throws Exception { } /** * Use the <code>setServerURL</code> method to set the URL of the server * you wish to connect to. * * @param serverURL a <code>String</code> value */ public void setServerURL(String serverURL) { this.serverURL = serverURL; } /** * Use the <code>setAdapterName</code> method to set the name the * adapter mbean is bound under in jndi. * * @param adapterName a <code>String</code> value */ public void setAdapterName(String adapterName) { this.adapterName = adapterName; } /** * Use the <code>setUsername</code> method to set the username for * the JMX invoker (if it's secured). * * @param username a <code>String</code> value */ public void setUsername(String username) { this.username = username; } /** * Use the <code>setPassword</code> method to set the password for * the JMX invoker (if it's secured). * * @param password a <code>String</code> value */ public void setPassword(String password) { this.password = password; } /** * Use the <code>addInvoke</code> method to add an <invoke> operation. * Include as attributes the target ObjectName and operation name. * Include as sub-elements parameters: see addParameter in the Invoke class. * * @param invoke an <code>Invoke</code> value */ public void addInvoke(Invoke invoke) { ops.add(invoke); } /** * Use the <code>addSetAttribute</code> method to add a set-attribute * operation. Include as attributes the target ObjectName and the * the attribute name. Include the value as a nested value tag * following the parameter syntax. * * @param setter a <code>Setter</code> value */ public void addSetAttribute(Setter setter) { ops.add(setter); } /** * Use the <code>addGetAttribute</code> method to add a get-attribute * operation. Include as attributes the target ObjectName, the * the attribute name, and a property name to hold the result of the * get-attribute operation. * * @param getter a <code>Getter</code> value */ public void addGetAttribute(Getter getter) { ops.add(getter); } /** * Use the <code>addPropertyEditor</code> method to make a PropertyEditor * available for values. Include attributes for the type and editor fully * qualified class name. * * @param peh a <code>PropertyEditorHolder</code> value */ public void addPropertyEditor(PropertyEditorHolder peh) { editors.add(peh); } /** * The <code>execute</code> method is called by ant to execute the task. * * @exception BuildException if an error occurs */ public void execute() throws BuildException { final ClassLoader origCL = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); try { for (int i = 0; i < editors.size(); i++) { editors.get(i).execute(); } // end of for () } catch (Exception e) { e.printStackTrace(); throw new BuildException("Could not register property editors: " + e); } // end of try-catch try { Properties props = new Properties(); String factory = "org.jnp.interfaces.NamingContextFactory"; if (username != null && password != null) { factory = "org.jboss.security.jndi.JndiLoginInitialContextFactory"; props.put(Context.SECURITY_PRINCIPAL, username); props.put(Context.SECURITY_CREDENTIALS, password); } props.put(Context.INITIAL_CONTEXT_FACTORY, factory); props.put(Context.URL_PKG_PREFIXES, "org.jboss.naming:org.jnp.interfaces"); if (serverURL == null || "".equals(serverURL)) { props.put(Context.PROVIDER_URL, "jnp://localhost:1099"); } else { props.put(Context.PROVIDER_URL, serverURL); } InitialContext ctx = new InitialContext(props); // if adapter is null, the use the default if (adapterName == null) { adapterName = "jmx/rmi/RMIAdaptor";//org.jboss.jmx.adaptor.rmi.RMIAdaptorService.DEFAULT_JNDI_NAME; } Object obj = ctx.lookup(adapterName); ctx.close(); if (!(obj instanceof MBeanServerConnection)) { throw new ClassCastException("Object not of type: MBeanServerConnection, but: " + (obj == null ? "not found" : obj.getClass().getName())); } MBeanServerConnection server = (MBeanServerConnection) obj; for (int i = 0; i < ops.size(); i++) { Operation op = ops.get(i); op.execute(server, this); } // end of for () } catch (Exception e) { e.printStackTrace(); throw new BuildException("problem: " + e); } // end of try-catch } finally { Thread.currentThread().setContextClassLoader(origCL); } } /** * The interface <code>Operation</code> provides a common interface * for the sub-tasks.. * */ public static interface Operation { void execute(MBeanServerConnection server, Task parent) throws Exception; } /** * The class <code>Invoke</code> specifies the invocation of a * managed operation. * */ public static class Invoke implements Operation { private ObjectName target; private String property; private String operation; private List<Param> params = new ArrayList<Param>(); /** * The <code>setProperty</code> method sets the name of the property * that will contain the result of the operation. * * @param property a <code>String</code> value */ public void setProperty(String property) { this.property = property; } /** * The <code>setTarget</code> method sets the ObjectName * of the target mbean. * * @param target an <code>ObjectName</code> value */ public void setTarget(ObjectName target) { this.target = target; } /** * The <code>setOperation</code> method specifies the operation to * be performed. * * @param operation a <code>String</code> value */ public void setOperation(String operation) { this.operation = operation; } /** * The <code>addParameter</code> method adds a parameter for * the operation. You must specify type and value. * * @param param a <code>Param</code> value */ public void addParameter(Param param) { params.add(param); } public void execute(MBeanServerConnection server, Task parent) throws Exception { int paramCount = params.size(); Object[] args = new Object[paramCount]; String[] types = new String[paramCount]; int pos = 0; for (int i = 0; i < params.size(); i++) { Param p = params.get(i); args[pos] = p.getValue(); types[pos] = p.getType(); pos++; } // end of for () Object result = server.invoke(target, operation, args, types); if ((property != null) && (result != null)) { parent.getProject().setProperty(property, result.toString()); } } } /** * The class <code>Setter</code> specifies setting an attribute * value on an mbean. * */ public static class Setter implements Operation { private ObjectName target; private String attribute; private Param value; /** * The <code>setTarget</code> method sets the ObjectName * of the target mbean. * * @param target an <code>ObjectName</code> value */ public void setTarget(ObjectName target) { this.target = target; } /** * The <code>setAttribute</code> method specifies the attribute to be set. * * @param attribute a <code>String</code> value */ public void setAttribute(String attribute) { this.attribute = attribute; } /** * The <code>setValue</code> method specifies the value to be used. * The type is used to convert the value to the correct type. * * @param value a <code>Param</code> value */ public void setValue(Param value) { this.value = value; } public void execute(MBeanServerConnection server, Task parent) throws Exception { Attribute att = new Attribute(attribute, value.getValue()); server.setAttribute(target, att); } } /** * The class <code>Getter</code> specifies getting an attribute * value of an mbean. * */ public static class Getter implements Operation { private ObjectName target; private String attribute; private String property; /** * The <code>setTarget</code> method sets the ObjectName * of the target mbean. * * @param target an <code>ObjectName</code> value */ public void setTarget(ObjectName target) { this.target = target; } /** * The <code>setAttribute</code> method specifies the attribute to be * retrieved. * * @param attribute a <code>String</code> value */ public void setAttribute(String attribute) { this.attribute = attribute; } /** * The <code>setProperty</code> method specifies the name of the property * to be set with the attribute value. * * @param property a <code>String</code> value */ public void setProperty(String property) { this.property = property; } public void execute(MBeanServerConnection server, Task parent) throws Exception { Object result = server.getAttribute(target, attribute); if ((property != null) && (result != null)) { parent.getProject().setProperty(property, result.toString()); } } } /** * The class <code>Param</code> is used to represent a object by * means of a string representation of its value and its type. * */ public static class Param { private String arg; private String type; /** * The <code>setArg</code> method sets the string representation * of the parameters value. * * @param arg a <code>String</code> value */ public void setArg(String arg) { this.arg = arg; } public String getArg() { return arg; } /** * The <code>setType</code> method sets the fully qualified class * name of the type represented by the param object. * * @param type a <code>String</code> value */ public void setType(String type) { this.type = type; } public String getType() { return type; } /** * The <code>getValue</code> method uses PropertyEditors to convert * the string representation of the value to an object, which it returns. * The PropertyEditor to use is determined by the type specified. * * @return an <code>Object</code> value * @exception Exception if an error occurs */ public Object getValue() throws Exception { PropertyEditor editor = PropertyEditors.getEditor(type); editor.setAsText(arg); return editor.getValue(); } } /** * The class <code>PropertyEditorHolder</code> allows you to add a * PropertyEditor to the default set. * */ public static class PropertyEditorHolder { private String type; private String editor; /** * The <code>setType</code> method specifies the return type from the * property editor. * * @param type a <code>String</code> value */ public void setType(final String type) { this.type = type; } public String getType() { return type; } private Class<?> getTypeClass() throws ClassNotFoundException { //with a little luck, one of these will work with Ant's classloaders try { return Class.forName(type); } catch (ClassNotFoundException e) { } // end of try-catch try { return getClass().getClassLoader().loadClass(type); } catch (ClassNotFoundException e) { } // end of try-catch return Thread.currentThread().getContextClassLoader().loadClass(type); } /** * The <code>setEditor</code> method specifies the fully qualified * class name of the PropertyEditor for the type specified in the type field. * * @param editor a <code>String</code> value */ public void setEditor(final String editor) { this.editor = editor; } public String getEditor() { return editor; } private Class<?> getEditorClass() throws ClassNotFoundException { //with a little luck, one of these will work with Ant's classloaders try { return Class.forName(editor); } catch (ClassNotFoundException e) { } // end of try-catch try { return getClass().getClassLoader().loadClass(editor); } catch (ClassNotFoundException e) { } // end of try-catch return Thread.currentThread().getContextClassLoader().loadClass(editor); } public void execute() throws ClassNotFoundException { PropertyEditorManager.registerEditor(getTypeClass(), getEditorClass()); } } }// JMX