| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.catalina.ant.jmx; |
| |
| import java.io.IOException; |
| import java.lang.reflect.Array; |
| import java.net.InetAddress; |
| import java.net.MalformedURLException; |
| import java.net.UnknownHostException; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.StringTokenizer; |
| |
| import javax.management.MBeanServerConnection; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.ObjectName; |
| import javax.management.openmbean.CompositeData; |
| import javax.management.openmbean.CompositeDataSupport; |
| import javax.management.openmbean.CompositeType; |
| import javax.management.openmbean.OpenType; |
| import javax.management.openmbean.SimpleType; |
| import javax.management.openmbean.TabularDataSupport; |
| import javax.management.remote.JMXConnector; |
| import javax.management.remote.JMXConnectorFactory; |
| import javax.management.remote.JMXServiceURL; |
| |
| import org.apache.catalina.ant.BaseRedirectorHelperTask; |
| import org.apache.tools.ant.BuildException; |
| import org.apache.tools.ant.Project; |
| |
| /** |
| * Access <em>JMX</em> JSR 160 MBeans Server. |
| * <ul> |
| * <li>open more then one JSR 160 rmi connection</li> |
| * <li>Get/Set Mbeans attributes</li> |
| * <li>Call Mbean Operation with arguments</li> |
| * <li>Argument values can be converted from string to |
| * int,long,float,double,boolean,ObjectName or InetAddress</li> |
| * <li>Query Mbeans</li> |
| * <li>Show Get, Call, Query result at Ant console log</li> |
| * <li>Bind Get, Call, Query result at Ant properties</li> |
| * </ul> |
| * |
| * Examples: open server with reference and autorisation |
| * |
| * <pre> |
| * |
| * <jmxOpen |
| * host="127.0.0.1" |
| * port="9014" |
| * username="monitorRole" |
| * password="mysecret" |
| * ref="jmx.myserver" |
| * /> |
| * |
| * </pre> |
| * |
| * All calls after opening with same refid reuse the connection. |
| * <p> |
| * First call to a remote MBeanserver save the JMXConnection a referenz |
| * <em>jmx.server</em> |
| * </p> |
| * All JMXAccessorXXXTask support the attribute <em>if</em> and |
| * <em>unless</em>. With <em>if</em> the task is only execute when property |
| * exist and with <em>unless</em> when property not exists. <br/><b>NOTE |
| * </b>: These tasks require Ant 1.6 or later interface. |
| * |
| * @author Peter Rossbach |
| * @version $Revision$ $Date$ |
| * @since 5.5.10 |
| */ |
| |
| public class JMXAccessorTask extends BaseRedirectorHelperTask { |
| |
| // ----------------------------------------------------- Instance Variables |
| |
| public static String JMX_SERVICE_PREFIX = "service:jmx:rmi:///jndi/rmi://"; |
| |
| public static String JMX_SERVICE_SUFFIX = "/jmxrmi"; |
| |
| private String name = null; |
| |
| private String resultproperty; |
| |
| private String url = null; |
| |
| private String host = "localhost"; |
| |
| private String port = "8050"; |
| |
| private String password = null; |
| |
| private String username = null; |
| |
| private String ref = "jmx.server"; |
| |
| private boolean echo = false; |
| |
| private boolean separatearrayresults = true; |
| |
| private String delimiter; |
| |
| private String unlessCondition; |
| |
| private String ifCondition; |
| |
| private Properties properties = new Properties(); |
| |
| // ----------------------------------------------------- Instance Info |
| |
| /** |
| * Descriptive information describing this implementation. |
| */ |
| private static final String info = "org.apache.catalina.ant.JMXAccessorTask/1.1"; |
| |
| /** |
| * Return descriptive information about this implementation and the |
| * corresponding version number, in the format |
| * <code><description>/<version></code>. |
| */ |
| public String getInfo() { |
| |
| return (info); |
| |
| } |
| |
| // ------------------------------------------------------------- Properties |
| |
| /** |
| * The name used at remote MbeanServer |
| */ |
| |
| public String getName() { |
| return (this.name); |
| } |
| |
| public void setName(String objectName) { |
| this.name = objectName; |
| } |
| |
| /** |
| * @return Returns the resultproperty. |
| */ |
| public String getResultproperty() { |
| return resultproperty; |
| } |
| |
| /** |
| * @param propertyName The resultproperty to set. |
| */ |
| public void setResultproperty(String propertyName) { |
| this.resultproperty = propertyName; |
| } |
| |
| /** |
| * @return Returns the delimiter. |
| */ |
| public String getDelimiter() { |
| return delimiter; |
| } |
| |
| /** |
| * @param separator The delimiter to set. |
| */ |
| public void setDelimiter(String separator) { |
| this.delimiter = separator; |
| } |
| |
| /** |
| * @return Returns the echo. |
| */ |
| public boolean isEcho() { |
| return echo; |
| } |
| |
| /** |
| * @param echo |
| * The echo to set. |
| */ |
| public void setEcho(boolean echo) { |
| this.echo = echo; |
| } |
| |
| /** |
| * @return Returns the separatearrayresults. |
| */ |
| public boolean isSeparatearrayresults() { |
| return separatearrayresults; |
| } |
| |
| /** |
| * @param separateArrayResults |
| * The separatearrayresults to set. |
| */ |
| public void setSeparatearrayresults(boolean separateArrayResults) { |
| this.separatearrayresults = separateArrayResults; |
| } |
| |
| /** |
| * The login password for the <code>Manager</code> application. |
| */ |
| public String getPassword() { |
| return (this.password); |
| } |
| |
| public void setPassword(String password) { |
| this.password = password; |
| } |
| |
| /** |
| * The login username for the <code>JMX</code> MBeanServer. |
| */ |
| public String getUsername() { |
| return (this.username); |
| } |
| |
| public void setUsername(String username) { |
| this.username = username; |
| } |
| |
| /** |
| * The URL of the <code>JMX JSR 160</code> MBeanServer to be used. |
| */ |
| |
| public String getUrl() { |
| return (this.url); |
| } |
| |
| public void setUrl(String url) { |
| this.url = url; |
| } |
| |
| /** |
| * The Host of the <code>JMX JSR 160</code> MBeanServer to be used. |
| */ |
| |
| public String getHost() { |
| return (this.host); |
| } |
| |
| public void setHost(String host) { |
| this.host = host; |
| } |
| |
| /** |
| * The Port of the <code>JMX JSR 160</code> MBeanServer to be used. |
| */ |
| |
| public String getPort() { |
| return (this.port); |
| } |
| |
| public void setPort(String port) { |
| this.port = port; |
| } |
| |
| /** |
| * @return Returns the useRef. |
| */ |
| public boolean isUseRef() { |
| return ref != null && !"".equals(ref); |
| } |
| |
| /** |
| * @return Returns the ref. |
| */ |
| public String getRef() { |
| return ref; |
| } |
| |
| /** |
| * @param refId The ref to set. |
| */ |
| public void setRef(String refId) { |
| this.ref = refId; |
| } |
| |
| /** |
| * @return Returns the ifCondition. |
| */ |
| public String getIf() { |
| return ifCondition; |
| } |
| |
| /** |
| * Only execute if a property of the given name exists in the current |
| * project. |
| * |
| * @param c property name |
| */ |
| public void setIf(String c) { |
| ifCondition = c; |
| } |
| |
| /** |
| * @return Returns the unlessCondition. |
| */ |
| public String getUnless() { |
| return unlessCondition; |
| } |
| |
| /** |
| * Only execute if a property of the given name does not exist in the |
| * current project. |
| * |
| * @param c property name |
| */ |
| public void setUnless(String c) { |
| unlessCondition = c; |
| } |
| |
| // --------------------------------------------------------- Public Methods |
| |
| /** |
| * Execute the specified command. This logic only performs the common |
| * attribute validation required by all subclasses; it does not perform any |
| * functional logic directly. |
| * |
| * @exception BuildException |
| * if a validation error occurs |
| */ |
| public void execute() throws BuildException { |
| if (testIfCondition() && testUnlessCondition()) { |
| try { |
| String error = null; |
| |
| MBeanServerConnection jmxServerConnection = getJMXConnection(); |
| error = jmxExecute(jmxServerConnection); |
| if (error != null && isFailOnError()) { |
| // exception should be thrown only if failOnError == true |
| // or error line will be logged twice |
| throw new BuildException(error); |
| } |
| } catch (Throwable t) { |
| if (isFailOnError()) { |
| throw new BuildException(t); |
| } else { |
| handleErrorOutput(t.getMessage()); |
| } |
| } finally { |
| closeRedirector(); |
| } |
| } |
| } |
| |
| /** |
| * create a new JMX Connection with auth when username and password is set. |
| */ |
| public static MBeanServerConnection createJMXConnection(String url, |
| String host, String port, String username, String password) |
| throws MalformedURLException, IOException { |
| String urlForJMX; |
| if (url != null) |
| urlForJMX = url; |
| else |
| urlForJMX = JMX_SERVICE_PREFIX + host + ":" + port |
| + JMX_SERVICE_SUFFIX; |
| Map environment = null; |
| if (username != null && password != null) { |
| String[] credentials = new String[2]; |
| credentials[0] = username; |
| credentials[1] = password; |
| environment = new HashMap(); |
| environment.put(JMXConnector.CREDENTIALS, credentials); |
| } |
| return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), |
| environment).getMBeanServerConnection(); |
| |
| } |
| |
| /** |
| * test the if condition |
| * |
| * @return true if there is no if condition, or the named property exists |
| */ |
| protected boolean testIfCondition() { |
| if (ifCondition == null || "".equals(ifCondition)) { |
| return true; |
| } |
| return getProperty(ifCondition) != null; |
| } |
| |
| /** |
| * test the unless condition |
| * |
| * @return true if there is no unless condition, or there is a named |
| * property but it doesn't exist |
| */ |
| protected boolean testUnlessCondition() { |
| if (unlessCondition == null || "".equals(unlessCondition)) { |
| return true; |
| } |
| return getProperty(unlessCondition) == null; |
| } |
| |
| /** |
| * Get Current Connection from <em>ref</em> parameter or create a new one! |
| * |
| * @return The server connection |
| * @throws MalformedURLException |
| * @throws IOException |
| */ |
| public static MBeanServerConnection accessJMXConnection(Project project, |
| String url, String host, String port, String username, |
| String password, String refId) throws MalformedURLException, |
| IOException { |
| MBeanServerConnection jmxServerConnection = null; |
| boolean isRef = project != null && refId != null && refId.length() > 0; |
| if (isRef) { |
| Object pref = project.getReference(refId); |
| try { |
| jmxServerConnection = (MBeanServerConnection) pref; |
| } catch (ClassCastException cce) { |
| if (project != null) { |
| project.log("wrong object reference " + refId + " - " |
| + pref.getClass()); |
| } |
| return null; |
| } |
| } |
| if (jmxServerConnection == null) { |
| jmxServerConnection = createJMXConnection(url, host, port, |
| username, password); |
| } |
| if (isRef && jmxServerConnection != null) { |
| project.addReference(refId, jmxServerConnection); |
| } |
| return jmxServerConnection; |
| } |
| |
| // ------------------------------------------------------ protected Methods |
| |
| /** |
| * get JMXConnection |
| * |
| * @return The connection |
| * @throws MalformedURLException |
| * @throws IOException |
| */ |
| protected MBeanServerConnection getJMXConnection() |
| throws MalformedURLException, IOException { |
| |
| MBeanServerConnection jmxServerConnection = null; |
| if (isUseRef()) { |
| Object pref = null ; |
| if(getProject() != null) { |
| pref = getProject().getReference(getRef()); |
| if (pref != null) { |
| try { |
| jmxServerConnection = (MBeanServerConnection) pref; |
| } catch (ClassCastException cce) { |
| getProject().log( |
| "Wrong object reference " + getRef() + " - " |
| + pref.getClass()); |
| return null; |
| } |
| } |
| } |
| if (jmxServerConnection == null) { |
| jmxServerConnection = accessJMXConnection(getProject(), |
| getUrl(), getHost(), getPort(), getUsername(), |
| getPassword(), getRef()); |
| } |
| } else { |
| jmxServerConnection = accessJMXConnection(getProject(), getUrl(), |
| getHost(), getPort(), getUsername(), getPassword(), null); |
| } |
| return jmxServerConnection; |
| } |
| |
| /** |
| * Execute the specified command, based on the configured properties. The |
| * input stream will be closed upon completion of this task, whether it was |
| * executed successfully or not. |
| * |
| * @exception Exception |
| * if an error occurs |
| */ |
| public String jmxExecute(MBeanServerConnection jmxServerConnection) |
| throws Exception { |
| |
| if ((jmxServerConnection == null)) { |
| throw new BuildException("Must open a connection!"); |
| } else if (isEcho()) { |
| handleOutput("JMX Connection ref=" + ref + " is open!"); |
| } |
| return null; |
| } |
| |
| /** |
| * Convert string to datatype FIXME How we can transfer values from ant |
| * project reference store (ref)? |
| * |
| * @param value The value |
| * @param valueType The type |
| * @return The converted object |
| */ |
| protected Object convertStringToType(String value, String valueType) { |
| if ("java.lang.String".equals(valueType)) |
| return value; |
| |
| Object convertValue = value; |
| if ("java.lang.Integer".equals(valueType) || "int".equals(valueType)) { |
| try { |
| convertValue = new Integer(value); |
| } catch (NumberFormatException ex) { |
| if (isEcho()) |
| handleErrorOutput("Unable to convert to integer:" + value); |
| } |
| } else if ("java.lang.Long".equals(valueType) |
| || "long".equals(valueType)) { |
| try { |
| convertValue = new Long(value); |
| } catch (NumberFormatException ex) { |
| if (isEcho()) |
| handleErrorOutput("Unable to convert to long:" + value); |
| } |
| } else if ("java.lang.Boolean".equals(valueType) |
| || "boolean".equals(valueType)) { |
| convertValue = new Boolean(value); |
| } else if ("java.lang.Float".equals(valueType) |
| || "float".equals(valueType)) { |
| try { |
| convertValue = new Float(value); |
| } catch (NumberFormatException ex) { |
| if (isEcho()) |
| handleErrorOutput("Unable to convert to float:" + value); |
| } |
| } else if ("java.lang.Double".equals(valueType) |
| || "double".equals(valueType)) { |
| try { |
| convertValue = new Double(value); |
| } catch (NumberFormatException ex) { |
| if (isEcho()) |
| handleErrorOutput("Unable to convert to double:" + value); |
| } |
| } else if ("javax.management.ObjectName".equals(valueType) |
| || "name".equals(valueType)) { |
| try { |
| convertValue = new ObjectName(value); |
| } catch (MalformedObjectNameException e) { |
| if (isEcho()) |
| handleErrorOutput("Unable to convert to ObjectName:" |
| + value); |
| } |
| } else if ("java.net.InetAddress".equals(valueType)) { |
| try { |
| convertValue = InetAddress.getByName(value); |
| } catch (UnknownHostException exc) { |
| if (isEcho()) |
| handleErrorOutput("Unable to resolve host name:" + value); |
| } |
| } |
| return convertValue; |
| } |
| |
| /** |
| * @param name context of result |
| * @param result |
| */ |
| protected void echoResult(String name, Object result) { |
| if (isEcho()) { |
| if (result.getClass().isArray()) { |
| for (int i = 0; i < Array.getLength(result); i++) { |
| handleOutput(name + "." + i + "=" + Array.get(result, i)); |
| } |
| } else |
| handleOutput(name + "=" + result); |
| } |
| } |
| |
| /** |
| * create result as property with name from attribute resultproperty |
| * |
| * @param result The result |
| * @see #createProperty(String, Object) |
| */ |
| protected void createProperty(Object result) { |
| if (resultproperty != null) { |
| createProperty(resultproperty, result); |
| } |
| } |
| |
| /** |
| * create result as property with name from property prefix When result is |
| * an array and isSeparateArrayResults is true, resultproperty used as |
| * prefix (<code>resultproperty.0-array.length</code> and store the |
| * result array length at <code>resultproperty.length</code>. Other |
| * option is that you delemit your result with a delimiter |
| * (java.util.StringTokenizer is used). |
| * |
| * @param propertyPrefix |
| * @param result |
| */ |
| protected void createProperty(String propertyPrefix, Object result) { |
| if (propertyPrefix == null) |
| propertyPrefix = ""; |
| if (result instanceof CompositeDataSupport) { |
| CompositeDataSupport data = (CompositeDataSupport) result; |
| CompositeType compositeType = data.getCompositeType(); |
| Set keys = compositeType.keySet(); |
| for (Iterator iter = keys.iterator(); iter.hasNext();) { |
| String key = (String) iter.next(); |
| Object value = data.get(key); |
| OpenType type = compositeType.getType(key); |
| if (type instanceof SimpleType) { |
| setProperty(propertyPrefix + "." + key, value); |
| } else { |
| createProperty(propertyPrefix + "." + key, value); |
| } |
| } |
| } else if (result instanceof TabularDataSupport) { |
| TabularDataSupport data = (TabularDataSupport) result; |
| for (Iterator iter = data.keySet().iterator(); iter.hasNext();) { |
| Object key = iter.next(); |
| for (Iterator iter1 = ((List) key).iterator(); iter1.hasNext();) { |
| Object key1 = iter1.next(); |
| CompositeData valuedata = data.get(new Object[] { key1 }); |
| Object value = valuedata.get("value"); |
| OpenType type = valuedata.getCompositeType().getType( |
| "value"); |
| if (type instanceof SimpleType) { |
| setProperty(propertyPrefix + "." + key1, value); |
| } else { |
| createProperty(propertyPrefix + "." + key1, value); |
| } |
| } |
| } |
| } else if (result.getClass().isArray()) { |
| if (isSeparatearrayresults()) { |
| int size = 0; |
| for (int i = 0; i < Array.getLength(result); i++) { |
| if (setProperty(propertyPrefix + "." + size, Array.get( |
| result, i))) { |
| size++; |
| } |
| } |
| if (size > 0) { |
| setProperty(propertyPrefix + ".Length", Integer |
| .toString(size)); |
| } |
| } |
| } else { |
| String delim = getDelimiter(); |
| if (delim != null) { |
| StringTokenizer tokenizer = new StringTokenizer(result |
| .toString(), delim); |
| int size = 0; |
| for (; tokenizer.hasMoreTokens();) { |
| String token = tokenizer.nextToken(); |
| if (setProperty(propertyPrefix + "." + size, token)) { |
| size++; |
| } |
| } |
| if (size > 0) |
| setProperty(propertyPrefix + ".Length", Integer |
| .toString(size)); |
| } else { |
| setProperty(propertyPrefix, result.toString()); |
| } |
| } |
| } |
| |
| /** |
| * get all properties, when project is there got all project Properties |
| * @return properties |
| */ |
| public Map getProperties() { |
| Project currentProject = getProject(); |
| if (currentProject != null) { |
| return currentProject.getProperties(); |
| } else { |
| return properties; |
| } |
| } |
| |
| /** |
| * get all Properties |
| * @param property |
| * @return The property |
| */ |
| public String getProperty(String property) { |
| Project currentProject = getProject(); |
| if (currentProject != null) { |
| return currentProject.getProperty(property); |
| } else { |
| return properties.getProperty(property); |
| } |
| } |
| |
| /** |
| * @param property The property |
| * @param value The value |
| * @return True if successful |
| */ |
| public boolean setProperty(String property, Object value) { |
| if (property != null) { |
| if (value == null) |
| value = ""; |
| if (isEcho()) { |
| handleOutput(property + "=" + value.toString()); |
| } |
| Project currentProject = getProject(); |
| if (currentProject != null) { |
| currentProject.setNewProperty(property, value.toString()); |
| } else { |
| properties.setProperty(property, value.toString()); |
| } |
| return true; |
| } |
| return false; |
| } |
| } |