001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ant;
023:
024: import java.beans.PropertyEditor;
025: import java.beans.PropertyEditorManager;
026: import java.util.ArrayList;
027: import java.util.List;
028: import java.util.Properties;
029: import javax.management.Attribute;
030: import javax.management.MBeanServerConnection;
031: import javax.management.ObjectName;
032: import javax.naming.Context;
033: import javax.naming.InitialContext;
034: import org.apache.tools.ant.BuildException;
035: import org.apache.tools.ant.Task;
036: import org.jboss.util.propertyeditor.PropertyEditors;
037:
038: /**
039: * JMX.java. An ant plugin to call managed operations and set attributes
040: * on mbeans in a jboss jmx mbean server.
041: * To use this plugin with Ant, place the jbossjmx-ant.jar together with the
042: * jboss jars jboss-j2ee.jar and jboss-common-client.jar, and the sun jnet.jar in the
043: * ant/lib directory you wish to use.
044: *
045: * Here is an example from an ant build file.
046: *
047: * <target name="jmx">
048: * <taskdef name="jmx"
049: * classname="org.jboss.ant.JMX"/>
050: * <jmx adapterName="jmx:HP.home.home:rmi">
051: *
052: * <propertyEditor type="java.math.BigDecimal" editor="org.jboss.util.propertyeditor.BigDecimalEditor"/>
053: * <propertyEditor type="java.util.Date" editor="org.jboss.util.propertyeditor.DateEditor"/>
054: *
055: *
056: * <!-- define classes -->
057: * <invoke target="fgm.sysadmin:service=DefineClasses"
058: * operation="defineClasses">
059: * <parameter type="java.lang.String" arg="defineclasses.xml"/>
060: * </invoke>
061: * </jmx>
062: *
063: *
064: * Created: Tue Jun 11 20:17:44 2002
065: *
066: * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
067: * @author <a href="mailto:dsnyder_lion@users.sourceforge.net">David Snyder</a>
068: * @version
069: */
070: public class JMX extends Task {
071: private String serverURL;
072:
073: private String adapterName = "jmx/invoker/RMIAdaptor";
074:
075: private List ops = new ArrayList();
076:
077: private List editors = new ArrayList();
078:
079: /**
080: * Creates a new <code>JMX</code> instance.
081: * Provides a default adapterName for the current server, so you only need to set it to
082: * talk to a remote server.
083: *
084: * @exception Exception if an error occurs
085: */
086: public JMX() throws Exception {
087: }
088:
089: /**
090: * Use the <code>setServerURL</code> method to set the URL of the server
091: * you wish to connect to.
092: *
093: * @param serverURL a <code>String</code> value
094: */
095: public void setServerURL(String serverURL) {
096: this .serverURL = serverURL;
097: }
098:
099: /**
100: * Use the <code>setAdapterName</code> method to set the name the
101: * adapter mbean is bound under in jndi.
102: *
103: * @param adapterName a <code>String</code> value
104: */
105: public void setAdapterName(String adapterName) {
106: this .adapterName = adapterName;
107: }
108:
109: /**
110: * Use the <code>addInvoke</code> method to add an <invoke> operation.
111: * Include as attributes the target ObjectName and operation name.
112: * Include as sub-elements parameters: see addParameter in the Invoke class.
113: *
114: * @param invoke an <code>Invoke</code> value
115: */
116: public void addInvoke(Invoke invoke) {
117: ops.add(invoke);
118: }
119:
120: /**
121: * Use the <code>addSetAttribute</code> method to add a set-attribute
122: * operation. Include as attributes the target ObjectName and the
123: * the attribute name. Include the value as a nested value tag
124: * following the parameter syntax.
125: *
126: * @param setter a <code>Setter</code> value
127: */
128: public void addSetAttribute(Setter setter) {
129: ops.add(setter);
130: }
131:
132: /**
133: * Use the <code>addGetAttribute</code> method to add a get-attribute
134: * operation. Include as attributes the target ObjectName, the
135: * the attribute name, and a property name to hold the result of the
136: * get-attribute operation.
137: *
138: * @param getter a <code>Getter</code> value
139: */
140: public void addGetAttribute(Getter getter) {
141: ops.add(getter);
142: }
143:
144: /**
145: * Use the <code>addPropertyEditor</code> method to make a PropertyEditor
146: * available for values. Include attributes for the type and editor fully
147: * qualified class name.
148: *
149: * @param peh a <code>PropertyEditorHolder</code> value
150: */
151: public void addPropertyEditor(PropertyEditorHolder peh) {
152: editors.add(peh);
153: }
154:
155: /**
156: * The <code>execute</code> method is called by ant to execute the task.
157: *
158: * @exception BuildException if an error occurs
159: */
160: public void execute() throws BuildException {
161: final ClassLoader origCL = Thread.currentThread()
162: .getContextClassLoader();
163: try {
164: Thread.currentThread().setContextClassLoader(
165: getClass().getClassLoader());
166: try {
167: for (int i = 0; i < editors.size(); i++) {
168: ((PropertyEditorHolder) editors.get(i)).execute();
169: } // end of for ()
170:
171: } catch (Exception e) {
172: e.printStackTrace();
173: throw new BuildException(
174: "Could not register property editors: " + e);
175: } // end of try-catch
176:
177: try {
178: Properties props = new Properties();
179: props.put(Context.INITIAL_CONTEXT_FACTORY,
180: "org.jnp.interfaces.NamingContextFactory");
181: props.put(Context.URL_PKG_PREFIXES,
182: "org.jboss.naming:org.jnp.interfaces");
183:
184: if (serverURL == null || "".equals(serverURL)) {
185: props.put(Context.PROVIDER_URL,
186: "jnp://localhost:1099");
187: } else {
188: props.put(Context.PROVIDER_URL, serverURL);
189: }
190: InitialContext ctx = new InitialContext(props);
191: ;
192:
193: // if adapter is null, the use the default
194: if (adapterName == null) {
195: adapterName = "jmx/rmi/RMIAdaptor";//org.jboss.jmx.adaptor.rmi.RMIAdaptorService.DEFAULT_JNDI_NAME;
196: }
197:
198: Object obj = ctx.lookup(adapterName);
199: ctx.close();
200:
201: if (!(obj instanceof MBeanServerConnection)) {
202: throw new ClassCastException(
203: "Object not of type: MBeanServerConnection, but: "
204: + (obj == null ? "not found" : obj
205: .getClass().getName()));
206: }
207:
208: MBeanServerConnection server = (MBeanServerConnection) obj;
209:
210: for (int i = 0; i < ops.size(); i++) {
211: Operation op = (Operation) ops.get(i);
212: op.execute(server, this );
213: } // end of for ()
214:
215: } catch (Exception e) {
216: e.printStackTrace();
217: throw new BuildException("problem: " + e);
218: } // end of try-catch
219: } finally {
220: Thread.currentThread().setContextClassLoader(origCL);
221: }
222:
223: }
224:
225: /**
226: * The interface <code>Operation</code> provides a common interface
227: * for the sub-tasks..
228: *
229: */
230: public static interface Operation {
231: void execute(MBeanServerConnection server, Task parent)
232: throws Exception;
233: }
234:
235: /**
236: * The class <code>Invoke</code> specifies the invocation of a
237: * managed operation.
238: *
239: */
240: public static class Invoke implements Operation {
241: private ObjectName target;
242: private String property;
243:
244: private String operation;
245:
246: private List params = new ArrayList();
247:
248: /**
249: * The <code>setProperty</code> method sets the name of the property
250: * that will contain the result of the operation.
251: *
252: * @param property a <code>String</code> value
253: */
254: public void setProperty(String property) {
255: this .property = property;
256: }
257:
258: /**
259: * The <code>setTarget</code> method sets the ObjectName
260: * of the target mbean.
261: *
262: * @param target an <code>ObjectName</code> value
263: */
264: public void setTarget(ObjectName target) {
265: this .target = target;
266: }
267:
268: /**
269: * The <code>setOperation</code> method specifies the operation to
270: * be performed.
271: *
272: * @param operation a <code>String</code> value
273: */
274: public void setOperation(String operation) {
275: this .operation = operation;
276: }
277:
278: /**
279: * The <code>addParameter</code> method adds a parameter for
280: * the operation. You must specify type and value.
281: *
282: * @param param a <code>Param</code> value
283: */
284: public void addParameter(Param param) {
285: params.add(param);
286: }
287:
288: public void execute(MBeanServerConnection server, Task parent)
289: throws Exception {
290: int paramCount = params.size();
291: Object[] args = new Object[paramCount];
292: String[] types = new String[paramCount];
293: int pos = 0;
294: for (int i = 0; i < params.size(); i++) {
295: Param p = (Param) params.get(i);
296: args[pos] = p.getValue();
297: types[pos] = p.getType();
298: pos++;
299: } // end of for ()
300: Object result = server.invoke(target, operation, args,
301: types);
302: if ((property != null) && (result != null)) {
303: parent.getProject().setProperty(property,
304: result.toString());
305: }
306: }
307: }
308:
309: /**
310: * The class <code>Setter</code> specifies setting an attribute
311: * value on an mbean.
312: *
313: */
314: public static class Setter implements Operation {
315: private ObjectName target;
316:
317: private String attribute;
318:
319: private Param value;
320:
321: /**
322: * The <code>setTarget</code> method sets the ObjectName
323: * of the target mbean.
324: *
325: * @param target an <code>ObjectName</code> value
326: */
327: public void setTarget(ObjectName target) {
328: this .target = target;
329: }
330:
331: /**
332: * The <code>setAttribute</code> method specifies the attribute to be set.
333: *
334: * @param attribute a <code>String</code> value
335: */
336: public void setAttribute(String attribute) {
337: this .attribute = attribute;
338: }
339:
340: /**
341: * The <code>setValue</code> method specifies the value to be used.
342: * The type is used to convert the value to the correct type.
343: *
344: * @param value a <code>Param</code> value
345: */
346: public void setValue(Param value) {
347: this .value = value;
348: }
349:
350: public void execute(MBeanServerConnection server, Task parent)
351: throws Exception {
352: Attribute att = new Attribute(attribute, value.getValue());
353: server.setAttribute(target, att);
354: }
355: }
356:
357: /**
358: * The class <code>Getter</code> specifies getting an attribute
359: * value of an mbean.
360: *
361: */
362: public static class Getter implements Operation {
363: private ObjectName target;
364:
365: private String attribute;
366:
367: private String property;
368:
369: /**
370: * The <code>setTarget</code> method sets the ObjectName
371: * of the target mbean.
372: *
373: * @param target an <code>ObjectName</code> value
374: */
375: public void setTarget(ObjectName target) {
376: this .target = target;
377: }
378:
379: /**
380: * The <code>setAttribute</code> method specifies the attribute to be
381: * retrieved.
382: *
383: * @param attribute a <code>String</code> value
384: */
385: public void setAttribute(String attribute) {
386: this .attribute = attribute;
387: }
388:
389: /**
390: * The <code>setProperty</code> method specifies the name of the property
391: * to be set with the attribute value.
392: *
393: * @param property a <code>String</code> value
394: */
395: public void setProperty(String property) {
396: this .property = property;
397: }
398:
399: public void execute(MBeanServerConnection server, Task parent)
400: throws Exception {
401: Object result = server.getAttribute(target, attribute);
402: if ((property != null) && (result != null)) {
403: parent.getProject().setProperty(property,
404: result.toString());
405: }
406: }
407: }
408:
409: /**
410: * The class <code>Param</code> is used to represent a object by
411: * means of a string representation of its value and its type.
412: *
413: */
414: public static class Param {
415: private String arg;
416: private String type;
417:
418: /**
419: * The <code>setArg</code> method sets the string representation
420: * of the parameters value.
421: *
422: * @param arg a <code>String</code> value
423: */
424: public void setArg(String arg) {
425: this .arg = arg;
426: }
427:
428: public String getArg() {
429: return arg;
430: }
431:
432: /**
433: * The <code>setType</code> method sets the fully qualified class
434: * name of the type represented by the param object.
435: *
436: * @param type a <code>String</code> value
437: */
438: public void setType(String type) {
439: this .type = type;
440: }
441:
442: public String getType() {
443: return type;
444: }
445:
446: /**
447: * The <code>getValue</code> method uses PropertyEditors to convert
448: * the string representation of the value to an object, which it returns.
449: * The PropertyEditor to use is determined by the type specified.
450: *
451: * @return an <code>Object</code> value
452: * @exception Exception if an error occurs
453: */
454: public Object getValue() throws Exception {
455: PropertyEditor editor = PropertyEditors.getEditor(type);
456: editor.setAsText(arg);
457: return editor.getValue();
458: }
459: }
460:
461: /**
462: * The class <code>PropertyEditorHolder</code> allows you to add a
463: * PropertyEditor to the default set.
464: *
465: */
466: public static class PropertyEditorHolder {
467: private String type;
468: private String editor;
469:
470: /**
471: * The <code>setType</code> method specifies the return type from the
472: * property editor.
473: *
474: * @param type a <code>String</code> value
475: */
476: public void setType(final String type) {
477: this .type = type;
478: }
479:
480: public String getType() {
481: return type;
482: }
483:
484: private Class getTypeClass() throws ClassNotFoundException {
485: //with a little luck, one of these will work with Ant's classloaders
486: try {
487: return Class.forName(type);
488: } catch (ClassNotFoundException e) {
489: } // end of try-catch
490: try {
491: return getClass().getClassLoader().loadClass(type);
492: } catch (ClassNotFoundException e) {
493: } // end of try-catch
494: return Thread.currentThread().getContextClassLoader()
495: .loadClass(type);
496: }
497:
498: /**
499: * The <code>setEditor</code> method specifies the fully qualified
500: * class name of the PropertyEditor for the type specified in the type field.
501: *
502: * @param editor a <code>String</code> value
503: */
504: public void setEditor(final String editor) {
505: this .editor = editor;
506: }
507:
508: public String getEditor() {
509: return editor;
510: }
511:
512: private Class getEditorClass() throws ClassNotFoundException {
513: //with a little luck, one of these will work with Ant's classloaders
514: try {
515: return Class.forName(editor);
516: } catch (ClassNotFoundException e) {
517: } // end of try-catch
518: try {
519: return getClass().getClassLoader().loadClass(editor);
520: } catch (ClassNotFoundException e) {
521: } // end of try-catch
522: return Thread.currentThread().getContextClassLoader()
523: .loadClass(editor);
524: }
525:
526: public void execute() throws ClassNotFoundException {
527: PropertyEditorManager.registerEditor(getTypeClass(),
528: getEditorClass());
529: }
530: }
531:
532: }// JMX
|