Following is a task that allows Ant to interact with the WebSphere AdminServer through the XMLConfig APIs. You can use it to configure, restore, start, and stop application servers (among other things) as part of a build. This is more robust than kicking off XMLConfig through the <exec> task or the <java> task, as it allows Ant to accurately report whether or not the WebSphere tasks were successful as a part of the build.
Below the source listing are an Ant build file and a XMLConfig script file demonstrating use. - Anthony -------------------------------------- package org.apache.tools.ant.taskdefs.optional.websphere; /** * Task to call WebSphere XMLConfig. * Requires IBM (WebSphere) JDK to run on all platforms except * for Solaris to avoid CORBA ORB ClassDefNotFoundErrors. * @author: <a href=mailto:[EMAIL PROTECTED]>Anthony J. Young-Garner</a> */ import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.InvocationTargetException; import java.io.File; public class XMLConfig extends org.apache.tools.ant.Task { public static boolean DEBUG = false; private static String XMLConfigClassname = "com.ibm.websphere.xmlconfig.XMLConfig"; private static String SASClientProps = "sas.client.props"; private AntClassLoader loader; private boolean inheritproperties = false; private String propertyprefix; private Path classpath; private File washome; private File xmlFile; private boolean exportFlag = true; private String adminNodeName; //required private boolean advancedFlag = true; private String nameServiceHost = "localhost"; private int nameServicePort = 900; private Class xmlConfigClass; private java.io.File javahome; /** * Borrowed code from AntClassLoader in 1.4 Build to support * setting the classloader context of the current thread. * When Ant 1.4 is released, this inner class should no longer * be necessary and all uses of the XMLConfigClassLoader in * the task may be replaced with the standard AntClassLoader. */ private class XMLConfigClassLoader extends AntClassLoader { /** * The context loader saved when setting the thread's current context loader. */ private ClassLoader savedContextLoader = null; private boolean isContextLoaderSaved = false; private Method getProtectionDomain = null; private Method defineClassProtectionDomain = null; private Method getContextClassLoader = null; private Method setContextClassLoader = null; public XMLConfigClassLoader(org.apache.tools.ant.Project project, Path classpath, boolean parent) { super(project, classpath, parent); try { getProtectionDomain = Class.class.getMethod("getProtectionDomain", new Class[0]); Class protectionDomain = Class.forName("java.security.ProtectionDomain"); Class[] args = new Class[] { String.class, byte[].class, Integer.TYPE, Integer.TYPE, protectionDomain }; defineClassProtectionDomain = ClassLoader.class.getDeclaredMethod("defineClass", args); getContextClassLoader = Thread.class.getMethod("getContextClassLoader", new Class[0]); args = new Class[] { ClassLoader.class }; setContextClassLoader = Thread.class.getMethod("setContextClassLoader", args); } catch (Exception e) { } } /** * Reset the current thread's context loader to its original value */ public void resetThreadContextLoader() { if (isContextLoaderSaved && getContextClassLoader != null && setContextClassLoader != null) { try { Object[] args = new Object[] { savedContextLoader }; setContextClassLoader.invoke(Thread.currentThread(), args); savedContextLoader = null; isContextLoaderSaved = false; } catch (InvocationTargetException ite) { Throwable t = ite.getTargetException(); throw new BuildException(t.toString()); } catch (Exception e) { throw new BuildException(e.toString()); } } } /** * Set the current thread's context loader to this classloader, storing the current * loader value for later resetting */ public void setThreadContextLoader() { if (isContextLoaderSaved) { throw new BuildException("Context loader has not been reset"); } if (getContextClassLoader != null && setContextClassLoader != null) { try { savedContextLoader = (ClassLoader) getContextClassLoader.invoke( Thread.currentThread(), new Object[0]); Object[] args = new Object[] { this }; setContextClassLoader.invoke(Thread.currentThread(), args); isContextLoaderSaved = true; } catch (InvocationTargetException ite) { Throwable t = ite.getTargetException(); throw new BuildException(t.toString()); } catch (Exception e) { throw new BuildException(e.toString()); } } } } /** * Creates the classpath for execution of XMLConfig * @return org.apache.tools.ant.types.Path */ public Path createClasspath() { if (this.classpath == null) { this.classpath = new Path(project); } return this.classpath.createPath(); } /** * Run the XMLConfig task. * If xmlFile attribute is null, a BuildException is thrown. * @exception org.apache.tools.ant.BuildException */ public void execute() throws BuildException { if (xmlFile == null && exportFlag == false) { throw new BuildException("xmlFile attribute is required", location); } if ((washome == null) || (("").equals(washome))) { throw new BuildException( "washome attribute or WAS_HOME environment variable must be set.", location); } if (javahome == null) { try { javahome = new java.io.File(washome.getCanonicalPath() + "/jdk"); } catch (java.io.IOException ioe) { if (DEBUG) ioe.printStackTrace(); throw new BuildException( "Could not convert washome attribute: " + washome + " to a valid canonical path."); } } if (classpath != null) { // replace next line with the one below it when this task is used with Ant 1.4 release. loader = new XMLConfigClassLoader(project, classpath, true); // this.loader = new AntClassLoader(project, classpath, true); } else { // replace next line with the one below it when this task is used with Ant 1.4 release. loader = new XMLConfigClassLoader(project, generateClasspath(washome.getAbsolutePath()), true); //this.loader = new AntClassLoader(project, generateClasspath(washome.getAbsolutePath()), true); } // replace next two lines with the one below them when this task is used with Ant 1.4 release. XMLConfigClassLoader specialLoader = (XMLConfigClassLoader) loader; specialLoader.setThreadContextLoader(); //loader.setThreadContextLoader(); try { System.setProperty("com.ibm.CORBA.ConfigURL", getConfigURL(washome)); System.setProperty("server.root", washome.getAbsolutePath()); } catch (java.net.MalformedURLException mue) { throw new BuildException("Could not create com.ibm.CORBA.ConfigURL environment variable"); } if (loadXMLConfigClass(XMLConfigClassname)) { try { Object xmlConfigObject = getXMLConfigObject(); if (inheritproperties) { //xmlConfigObject.setVariableReplacementPairs(getProject().getProperties()); Class[] parmClasses = new Class[1]; parmClasses[0] = java.util.Hashtable.class; java.lang.reflect.Method methodSetVariableReplacementPairs = xmlConfigClass.getMethod("setVariableReplacementPairs", parmClasses); Object[] argObjects = new Object[1]; argObjects[0] = getProject().getProperties(); methodSetVariableReplacementPairs.invoke(xmlConfigObject, argObjects); } if (exportFlag) { if (xmlFile != null) { //xmlConfigObject.executePartialExport(xmlFile); Class[] parmClasses = new Class[1]; parmClasses[0] = java.io.File.class; java.lang.reflect.Method methodExecutePartialExport = xmlConfigClass.getMethod("executePartialExport", parmClasses); Object[] argObjects = new Object[1]; argObjects[0] = xmlFile; methodExecutePartialExport.invoke(xmlConfigObject, argObjects); } else { //xmlConfigObject.executeFullExport(); Class[] parmClasses = new Class[0]; // parmClasses[0] = NO ARGS java.lang.reflect.Method methodExecuteFullExport = xmlConfigClass.getMethod("executeFullExport", parmClasses); Object[] argObjects = new Object[0]; //argObjects[0] = NO ARGS methodExecuteFullExport.invoke(xmlConfigObject, argObjects); } } else { //xmlConfigObject.importFromFile(xmlFile); Class[] parmClasses = new Class[1]; parmClasses[0] = java.io.File.class; java.lang.reflect.Method methodImportFromFile = xmlConfigClass.getMethod("importFromFile", parmClasses); Object[] argObjects = new Object[1]; argObjects[0] = xmlFile; methodImportFromFile.invoke(xmlConfigObject, argObjects); } logWarnings(xmlConfigObject); failOnErrors(xmlConfigObject); } catch (InvocationTargetException ite) { if (DEBUG) ite.printStackTrace(); throw new BuildException("XMLConfig InvocationTargetException. WAS AdminServer may not be running on " + nameServiceHost + ":" + nameServicePort +". Also, IBM (WAS) JDK may not have been used to run Ant."); } catch (InstantiationException ie) { if (DEBUG) ie.printStackTrace(); throw new BuildException("XMLConfig InstantiationException."); } catch (IllegalAccessException iae) { if (DEBUG) iae.printStackTrace(); throw new BuildException("XMLConfig IllegalAccessException."); } catch (NoSuchMethodException nsme) { if (DEBUG) nsme.printStackTrace(); throw new BuildException("Could not find XMLConfig constructor. Raro."); } catch (BuildException be) { if (DEBUG) be.printStackTrace(); throw new BuildException(be.getMessage()); } catch (Exception iae) { //should be a com.ibm.websphere.xmlconfig.InvalidArgumentException if (DEBUG) iae.printStackTrace(); throw new BuildException("XML file: " + xmlFile + " is invalid."); } specialLoader.resetThreadContextLoader(); } else { throw new BuildException("Could not find XMLConfig class. Check classpath."); } } /** * Retrieve and fail on errors from the XMLConfig object. */ private void failOnErrors(Object xmlConfigObject) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class[] parmClassesA = new Class[0]; //parmClasses[0] = NO ARGS java.lang.reflect.Method methodGetNoOfErrors = xmlConfigClass.getMethod("getNoOfErrors", parmClassesA); Object[] argObjectsA = new Object[0]; //argObjects[0] = NO ARGS Object returnValA = methodGetNoOfErrors.invoke(xmlConfigObject, argObjectsA); int errorCount = ((Integer)returnValA).intValue(); if (errorCount > 0) { Class[] parmClassesB = new Class[0]; //parmClasses[0] = NO ARGS java.lang.reflect.Method methodGetErrors = xmlConfigClass.getMethod("getErrors", parmClassesB); Object[] argObjectsB = new Object[0]; //argObjects[0] = NO ARGS Object returnValB = methodGetErrors.invoke(xmlConfigObject, argObjectsB); java.util.Vector errors = (java.util.Vector)returnValB; StringBuffer buffer = new StringBuffer(); for (int i=0; i < errorCount; i++) { buffer.append((String)errors.elementAt(i)); } throw new BuildException("\n\nXMLConfig Failures\n------------------\n" + buffer); } } /** * Generate classpath environment necessary to run XMLConfig based on "washome" property. */ private Path generateClasspath(String washome) { StringBuffer path = new StringBuffer(); path.append(washome + "\\lib\\ibmwebas.jar;"); path.append(washome + "\\lib\\servlet.jar;"); path.append(washome + "\\lib\\xml4j.jar;"); path.append(washome + "\\lib\\ujc.jar;"); path.append(washome + "\\lib\\ejs.jar;"); path.append(washome + "\\lib\\console.jar;"); path.append(washome + "\\lib\\admin.jar;"); path.append(washome + "\\lib\\repository.jar;"); path.append(washome + "\\lib\\sslight.jar;"); path.append(washome + "\\lib\\tasks.jar;"); path.append(washome + "\\lib\\ivjejb35.jar;"); path.append(washome + "\\properties;"); path.append(javahome + "\\lib\\tools.jar"); if (DEBUG) log(path.toString()); return new Path(this.project, path.toString()); } /** * Returns the name of the AdminNode that XMLConfig * should attempt to access. * @return java.lang.String */ public java.lang.String getAdminNodeName() { return adminNodeName; } /** * Returns the classpath for the execution of this task. * @return org.apache.tools.ant.types.Path */ public org.apache.tools.ant.types.Path getClasspath() { return classpath; } /** * Get URL for sas.client.props file based on "washome" attribute. */ private String getConfigURL(java.io.File washome) throws java.net.MalformedURLException { String filename = washome.getAbsolutePath(); java.io.File sasFile = new java.io.File(filename+"\\properties\\sas.client.props"); java.net.URL url = sasFile.toURL(); return url.toString(); } /** * Insert the method's description here. * Creation date: (8/23/2001 12:20:26 PM) * @return java.io.File */ public java.io.File getJavahome() { return javahome; } /** * Returns the hostname on which XMLConfig should * attempt to access the WAS JNDI Name Services. * @return java.lang.String */ public java.lang.String getNameServiceHost() { return nameServiceHost; } /** * Returns the port on which XMLConfig should attempt * to access the WAS JNDI Name Service. * @return int */ public int getNameServicePort() { return nameServicePort; } /** * UNIMPLEMENTED * Returns the prefix of properties that should * be passed through to the XMLConfig class as * variable replacement pairs (see XMLConfig docs * in WebSphere InfoCenter). If empty string ("") * is returned, all project properties will be * passed. * @see isInheritproperties, setInheritproperties * @return java.lang.String */ public java.lang.String getPropertyprefix() { return propertyprefix; } /** * Returns the location where this * task expects to find WebSphere * installed (e.g. "C:\WebSphere\AppServer"). * @return java.io.File */ public java.io.File getWashome() { return washome; } /** * Returns a WebSphere XMLConfig object. */ private Object getXMLConfigObject() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class[] parmTypes = new Class[4]; parmTypes[0] = adminNodeName.getClass(); parmTypes[1] = java.lang.Boolean.TYPE; parmTypes[2] = nameServiceHost.getClass(); parmTypes[3] = Integer.TYPE; Constructor constructor = xmlConfigClass.getConstructor(parmTypes); if (advancedFlag) { Class[] parms = new Class[1]; parms[0] = new String().getClass(); java.lang.reflect.Method qualifyMethod = xmlConfigClass.getMethod("qualifyName", parms); Object[] methodparms = new Object[1]; methodparms[0] = adminNodeName; qualifyMethod.invoke(null, methodparms); } Object[] parms = new Object[4]; parms[0] = adminNodeName; parms[1] = new Boolean(advancedFlag); parms[2] = nameServiceHost; parms[3] = new Integer(nameServicePort); //com.ibm.websphere.xmlconfig.XMLConfig xmlConfigObject = (com.ibm.websphere.xmlconfig.XMLConfig) constructor.newInstance(parms); Object xmlConfigObject = constructor.newInstance(parms); return xmlConfigObject; } /** * Returns the xml file that will * be passed to the XMLConfig class * by this task. * @return java.io.File */ public java.io.File getXmlFile() { return xmlFile; } /** * Initializes this task. */ public void init() { super.init(); String wasSysProp = System.getProperty("WAS_HOME"); if (wasSysProp != null) { washome = new java.io.File(System.getProperty("WAS_HOME")); } inheritproperties = false; propertyprefix = ""; } /** * Returns <code>true</code> if XMLConfig will * be contacting a WAS Advanced Server or * <code>false</code> if XMLConfig will be * contacting a WAS Standard Server. * @return boolean */ public boolean isAdvancedFlag() { return advancedFlag; } /** * Returns <code>true</code> if XMLConfig will * be performing a full or partial export operation. * Returns <code>false</code> if XMLConfig will * be performing a import operation. * @return boolean */ public boolean isExportFlag() { return exportFlag; } /** * Returns a boolean indicating whether * project properties should be passed * through to the XMLConfig class as * variable substitution pairs. * @see getPropertyprefix, setPropertyprefix * @return boolean */ public boolean isInheritproperties() { return inheritproperties; } /** * Loads the class specified in "className" into "loader" */ private Class loadClass(String className, ClassLoader loader) throws ClassNotFoundException { if (loader != null) { if (loader.getClass().isAssignableFrom(AntClassLoader.class)) { return ((AntClassLoader)loader).forceLoadClass(className); } else { return loader.loadClass(className); } } else { return Class.forName(className); } } /** * Borrowed from <code>org.apache.tools.ant.taskdefs.Available</code>. * Returns true if "classname" can be found on any available classloader. * Otherwise returns false. * @return boolean */ private boolean loadXMLConfigClass(String classname) { try { if (loader != null) { xmlConfigClass = loadClass(classname, loader); } else { ClassLoader l = this.getClass().getClassLoader(); // Can return null to represent the bootstrap class loader. // see API docs of Class.getClassLoader. if (l != null) { xmlConfigClass = loadClass(classname, l); } else { xmlConfigClass = loadClass(classname, null); } } return true; } catch (ClassNotFoundException e) { if (DEBUG) e.printStackTrace(); return false; } catch (NoClassDefFoundError e) { if (DEBUG) e.printStackTrace(); return false; } } /** * Retrieve and log warnings from the XMLConfig object. */ private void logWarnings(Object xmlConfigObject) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException { Class[] parmClassesA = new Class[0]; //parmClasses[0] = NO ARGS java.lang.reflect.Method methodGetNoOfWarnings = xmlConfigClass.getMethod("getNoOfWarnings", parmClassesA); Object[] argObjectsA = new Object[0]; //argObjects[0] = NO ARGS Object returnValA = methodGetNoOfWarnings.invoke(xmlConfigObject, argObjectsA); int warningCount = ((Integer)returnValA).intValue(); if (warningCount > 0) { Class[] parmClassesB = new Class[0]; //parmClasses[0] = NO ARGS java.lang.reflect.Method methodGetWarnings = xmlConfigClass.getMethod("getWarnings", parmClassesB); Object[] argObjectsB = new Object[0]; //argObjects[0] = NO ARGS Object returnValB = methodGetWarnings.invoke(xmlConfigObject, argObjectsB); java.util.Vector warnings = (java.util.Vector)returnValB; for (int i=0; i < warningCount; i++) { log((String)warnings.elementAt(i)); } } } /** * Sets the hostname on which XMLConfig should * attempt to access the WAS JNDI Name Services. * @param newAdminNodeName java.lang.String */ public void setAdminNodeName(java.lang.String newAdminNodeName) { adminNodeName = newAdminNodeName; } /** * Sets whether XMLConfig will (true) * be contacting a WAS Advanced Server * or (false) a WAS Standard Server. * @param newAdvancedFlag boolean */ public void setAdvancedFlag(boolean newAdvancedFlag) { advancedFlag = newAdvancedFlag; } /** * Amends the classpath to be used to run XMLConfig. * @param newClasspath org.apache.tools.ant.types.Path Must not be null. */ public void setClasspath(org.apache.tools.ant.types.Path newClasspath) { if (classpath == null) { classpath = newClasspath; } else { classpath.append(newClasspath); } } /** * Adds a reference to a CLASSPATH defined elsewhere. * @param newClasspath org.apache.tools.ant.types.Reference Must not be null. */ public void setClasspathRef(Reference r) { createClasspath().setRefid(r); } /** * Sets whether XMLConfig will be performing * an export operation (true) or an import * operation (false). * @param newExportFlag boolean */ public void setExportFlag(boolean newExportFlag) { exportFlag = newExportFlag; } /** * Sets whether Ant project properties will be passed * through to XMLConfig class as variable substitution * pairs. Default is false. * @param newInheritproperties boolean */ public void setInheritproperties(boolean newInheritproperties) { inheritproperties = newInheritproperties; } /** * Sets the location where this * task should expect to find the JDK * installed (e.g. "C:\WebSphere\AppServer\jdk"). * @param newJavahome java.io.File */ public void setJavahome(java.io.File newJavahome) { javahome = newJavahome; } /** * Sets the hostname on which XMLConfig should * attempt to access the WAS JNDI Name Services. * @param newNameServiceHost java.lang.String */ public void setNameServiceHost(java.lang.String newNameServiceHost) { nameServiceHost = newNameServiceHost; } /** * Sets the port on which XMLConfig should attempt * to access the WAS JNDI Name Service. * @param newNameServicePort int */ public void setNameServicePort(int newNameServicePort) { nameServicePort = newNameServicePort; } /** * UNIMPLEMENTED * Sets the prefix of Ant project properties that * should be passed through to the XMLConfig class. * If prefix is empty string (""), all project properties * will be passed; this is the default. * @see getPropertyprefix, setInheritproperties * @param newPropertyprefix java.lang.String */ public void setPropertyprefix(java.lang.String newPropertyprefix) { propertyprefix = newPropertyprefix; } /** * Sets the location where this * task should expect to find WebSphere * installed (e.g. "C:\WebSphere\AppServer"). * @param newWashome java.io.File */ public void setWashome(java.io.File newWashome) { washome = newWashome; } /** * Sets the xml file that will * be passed to the XMLConfig class * by this task. * @param newXmlFile java.io.File */ public void setXmlFile(java.io.File newXmlFile) { xmlFile = newXmlFile; } } --------------------------------------- <?xml version="1.0"?> <project name="XMLConfigExample" default="main" basedir="."> <taskdef name="xmlconfig" classname="org.apache.tools.ant.taskdefs.optional.websphere.XMLConfig"/> <target name="main"> <!-- <javac srcdir="." destdir="." verbose="on"/> --> <property name="nodename" value="neverstop"/> <property name="servername" value="Default Server"/> <property name="serveraction" value="stop"/> <xmlconfig adminNodeName="neverstop" advancedFlag="true" exportFlag="false" inheritProperties="true" washome="C:\WebSphere\AppServer" xmlFile="C:\temp\toggleAppServer.xml" /> </target> </project> ----------------------------------- <?xml version="1.0"?> <!DOCTYPE websphere-sa-config SYSTEM "$server_root$$dsep$bin$dsep$xmlconfig.dtd" > <websphere-sa-config> <node name="$nodename$" action="locate"> <application-server name="$servername$" action="$serveraction$"> </application-server> </node> </websphere-sa-config> -------------------------------- __________________________________________________ Do You Yahoo!? Make international calls for as low as $.04/minute with Yahoo! Messenger http://phonecard.yahoo.com/
