/**
* Copyright 2007 ATG DUST Project
*
* Licensed 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 atg.junit.nucleus;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.jar.Manifest;
import javax.activation.DataHandler;
import javax.activation.FileDataSource;
import javax.mail.BodyPart;
import javax.mail.Message;
import javax.mail.Multipart;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMultipart;
import org.apache.log4j.Logger;
import org.w3c.dom.Node;
import atg.applauncher.AppLauncher;
import atg.applauncher.AppModule;
import atg.nucleus.DynamoEnv;
import atg.nucleus.Nucleus;
import atg.service.email.ContentPart;
import atg.service.email.EmailEvent;
import atg.service.email.MimeMessageUtils;
import atg.service.email.SMTPEmailSender;
import atg.servlet.ServletUtil;
/**
* This class is used to hold useful utilty methods people may
* need when running tests.
*/
public class TestUtils
extends atg.nucleus.GenericService
{
private static Logger log = Logger.getLogger(TestUtils.class);
// names of app servers types that may be specified by the
// 'atg.dynamo.appserver' system property
// Dynamo currently does not distinguish between generic
// Tomcat and JBoss, everything is just referred to as 'tomcat'
public static final String APP_SERVER_DAS = "das";
public static final String APP_SERVER_BEA = "weblogic";
public static final String APP_SERVER_IBM = "websphere";
public static final String APP_SERVER_TOMCAT = "tomcat";
// names of various vendors that ATG works with
public static final String VENDOR_ATG = "ATG";
public static final String VENDOR_BEA = "BEA";
public static final String VENDOR_IBM = "IBM";
public static final String VENDOR_JBOSS = "JBOSS";
// the variable that points to the installation directory for dynamo
private static final String ROOT_VAR = "atg.dynamo.root";
private static final String HOME_VAR = "atg.dynamo.home";
private static final String ATG_J2EESERVER_ROOT = "atg.j2eeserver.root";
// these are used to lookup some system settings from the VM
private static final String JAVA_VAR = "java.vm.info";
private static final String JAVA_VERSION = "java.vm.version";
private static final String JAVA_BUILD_VERSION = "java.version";
private static final String COMPILER_VAR = "java.compiler";
private static final String OS_VAR = "os.name";
private static final String OS_VERSION_VAR = "os.version";
// the system variable that returns the name of the app server being used
private static final String APP_SERVER = "atg.dynamo.appserver";
// the Configuration component used by Dynamo
private static final String CONFIGURATION_COMPONENT = "/atg/dynamo/Configuration";
// mailhost used to send email
private static final String MAILHOST = "mailsvr.atg.com";
// value returned by several methods, as noted in javadoc, if a
// piece of information can not be definitively determined. in
// particular, used when reporting about product build and version
// information
public static final String UNKNOWN_INFO = "unknown";
/** property to track the DUST version being used. utilized by
* ATGXMLFileTestResultReported so we can tag XML result files for
* compatibility validation when passed to the XML file logger */
public static int DUST_VERSION = 1;
/** specifies the DUST version being used. utilized by
* ATGXMLFileTestResultReporter so XML result files can be tagged
* for compatibility validation when passed to the XML file
* logger */
public void setDustVersion( int pVersion ) { DUST_VERSION = pVersion; }
/** returns the DUST version being used. utilized by
* ATGXMLFileTestResultReporter so XML result files can be tagged
* for compatibility validation when passed to the XML file
* logger */
public int getDustVersion() { return DUST_VERSION; }
/** property to track the DUST user. utilized when results are
* logged to the database to correlate the result with a user
* account in the test management system. */
public static String DUST_USERNAME = System.getProperty( "user.name" );
/** specifies the DUST user. utilized when results are logged to
* the database to correlate the result with a user account in the
* test management system. */
public void setDustUsername( String pUsername ) { DUST_USERNAME = pUsername; }
/** returns the DUST user name. utilized when results are logged to
* the database to correlate the result with a user account in the
* test management system. */
public String getDustUsername() {
if ( DUST_USERNAME == null || DUST_USERNAME.trim().length() == 0 )
return System.getProperty( "user.name" );
else return DUST_USERNAME;
}
/** property to track which testrun a result is part of. utilized
* by TSM to correlate a specifid result with the testrun used to
* install and configure the test Dynamo. */
public static String TSM_TESTRUN = null;
/** Specifies the TSM testrun this result is part of. utilized by
* TSM to correlate a specifid result with the testrun used to
* install and configure the test Dynamo. */
public void setTsmTestrun( String pId ) { TSM_TESTRUN = pId; }
/** Returns the TSM testrun this result is part of. utilized by TSM
* to correlate a specifid result with the testrun used to install
* and configure the test Dynamo. */
public String getTsmTestrun() { return TSM_TESTRUN; }
/** property to track the p4 sync time for tests. utilized by TSM
* to inform end-users of time at which machine was last synced.
* must be specified by test setup before test is run. */
public static String P4SYNCTIME = null;
/** property to track the p4 sync time for tests. utilized by TSM
* to inform end-users of time at which machine was last synced.
* must be specified by test setup before test is run. */
public void setP4Synctime( String pTime ) { P4SYNCTIME = pTime; }
/** property to track the p4 sync time for tests. utilized by TSM
* to inform end-users of time at which machine was last synced.
* must be specified by test setup before test is run. */
public String setP4Synctime() { return P4SYNCTIME; }
/** Returns the directory in which Dynamo was installed. If the
* installation directory was not specified during the DUST
* installation, returns null. Should <b>only</b> be used by
* System tests. */
public static File DYNAMO_INSTALL_DIR = null;
/** Returns the directory in which Dynamo was installed. If the
* installation directory can not be successfully determined returns
* null.
* <br><b>NOTE:</b> There is no reliable System property (or
* other inherent mechanism) to determine the Dynamo installation
* directory when running as BigEar, so this value is set during the
* DUST build process. The SystemTests.base build step writes the
* file
* SystemTests/base/config/atg/junit/nucleus/TestUtils.properties
* with the proper value. Consequently, this method should only be
* used by System tests, not Unit tests.
*/
public File getDynamoInstallDir() { return DYNAMO_INSTALL_DIR; }
/** Specifies the directory in which Dynamo was installed. */
public void setDynamoInstallDir( File pDir ) { DYNAMO_INSTALL_DIR = pDir; }
/** Returns the root directory for this Dynamo. If the root
* directory can not be successfully located returns null. Operates
* according to this logic:
* <ul>
* <li>If "home" Dynamo module can be found, return parent directory
* containing that module. (This should resolve when running 'BigEar')
* <li>Otherwise, return value of System property 'atg.dynamo.root'.
* (this could still be null)
* </ul>
*/
public static File getDynamoRootDir() {
File root = null;
try { root = getDynamoHomeDir().getParentFile(); }
catch (Throwable t) {}
if ( root == null ) {
try { root = new File( System.getProperty( ROOT_VAR ) ); }
catch (Throwable t) {}
}
return root;
}
/** Returns Dynamo's "home" module installation directory. If the
* directory can not be successfully located returns null.
* <br>Logic works like this:
* <ul>
* <li>If "home" Dynamo module can be found, return directory representing
* that module. This should resolve when running 'BigEar' and may
* point to a subdirectory of the application server's directory used
* to deploy ear files. On DAS it should resolve to
* <DYNAMO_INSTALL_DIR>/home.
* <li>Otherwise, return value of System property 'atg.dynamo.home'.
* (this could be null)
* </ul>
*/
public static File getDynamoHomeDir() {
File root = null;
try { root = getModuleResourceFile("home",".").getCanonicalFile(); }
catch (Throwable t) {}
if ( root == null ) {
try { root = new File( System.getProperty( HOME_VAR ) ); }
catch (Throwable t) {}
}
return root;
}
/** returns the root install directory for the ATG J2EE Server, or null if
* the ATG J2EE Server is not installed. */
public static File getAtgJ2eeServerInstallDir() {
try { return new File(System.getProperty( ATG_J2EESERVER_ROOT )); }
catch (Throwable t) { return null; }
}
/** Returns the product name of the app server being used. For ATG
* we currently assume it's called 'ATGDAS' if it's a separate
* product, since there is no definitive way to figure out the
* product name from MANIFEST files. For all other app servers it
* returns the value of getAppServerType().
*/
public static String getAppServerProductName() {
if ( getAppServerType().equals( APP_SERVER_DAS ) ) return getAtgJ2eeServerProductName();
else return getAppServerType();
}
/** Returns the name of the ATG J2EE Server product this is installed, or
* null if a separate ATG J2EE Server build is not installed. */
public static String getAtgJ2eeServerProductName() {
// TODO: Bug 78552 was opened to add a MANIFEST entry containing
// the product name so we don't have to hard code this to
// 'ATGDAS'.
if ( getAtgJ2eeServerInstallDir() != null ) return "ATGDAS";
else return null;
}
/** Returns the version number of the app server being used. For
* DAS this version comes from the J2EEServer MANIFEST file, or is
* UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
* case if a person is using devtools to build their product. For
* 3PAS the version number is extracted from their configuration
* file (typically some well known XML file).
*/
public static String getAppServerVersion() {
String apptype = getAppServerType();
if ( apptype.equals( APP_SERVER_DAS ) ) {
return getAtgVersion( getAtgJ2eeServerModule() );
} else if ( apptype.equals( APP_SERVER_BEA ) ) {
return getBeaVersion();
} else if ( apptype.equals( APP_SERVER_IBM ) ) {
return getWasVersion();
} else if ( apptype.equals( APP_SERVER_TOMCAT ) ) {
return getJBossVersion();
} else {
return UNKNOWN_INFO;
}
}
/** Returns the build number of the app server being used. For DAS
* this version comes from the J2EEServer MANIFEST file, or is
* UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
* case if a person is using devtools to build their product. For
* 3PAS the build number is always UNKNOWN_INFO.
*/
public static String getAppServerBuildNumber() {
String apptype = getAppServerType();
if ( apptype.equals( APP_SERVER_DAS ) ) {
return getAtgBuildNumber( getAtgJ2eeServerModule() );
} else {
return UNKNOWN_INFO;
}
}
/** Returns the patch version of the app server being used. For DAS
* this version comes from the J2EEServer MANIFEST file, or is
* UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
* case if a person is using devtools to build their product. For
* 3PAS the patch version is always UNKNOWN_INFO.
*/
public static String getAppServerPatchVersion() {
String apptype = getAppServerType();
if ( apptype.equals( APP_SERVER_DAS ) ) {
return getAtgPatchVersion( getAtgJ2eeServerModule() );
} else {
return UNKNOWN_INFO;
}
}
/** Returns the patch build number of the app server being used.
* For DAS this version comes from the J2EEServer MANIFEST file, or
* is UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
* case if a person is using devtools to build their product. For
* 3PAS the patch build number is always UNKNOWN_INFO.
*/
public static String getAppServerPatchBuildNumber() {
String apptype = getAppServerType();
if ( apptype.equals( APP_SERVER_DAS ) ) {
return getAtgPatchBuildNumber( getAtgJ2eeServerModule() );
} else {
return UNKNOWN_INFO;
}
}
/** Returns the vendor name of the App server manufacturer. if a
* vendor can not be determined it returns UNKNOWN_INFO.
*/
public static String getAppServerVendor() {
String apptype = getAppServerType();
if ( apptype.equals( APP_SERVER_DAS ) ) {
return VENDOR_ATG;
} else if ( apptype.equals( APP_SERVER_BEA ) ) {
return VENDOR_BEA;
} else if ( apptype.equals( APP_SERVER_IBM ) ) {
return VENDOR_IBM;
} else if ( apptype.equals( APP_SERVER_TOMCAT ) ) {
return VENDOR_JBOSS;
} else {
return UNKNOWN_INFO;
}
}
/** Returns true if the Dynamo product is being used; false if only the ATG
* J2EE Server product is running.
**/
public static boolean isDynamoInstalled()
{
try {
// if j2ee server is not installed then Dynamo must be...
if ( getAtgJ2eeServerInstallDir() == null ) return true;
// if the j2ee server root is the same as the dynamo root then
// we're running only the j2ee server
else return ( ! getAtgJ2eeServerInstallDir().getCanonicalFile().equals(getDynamoRootDir().getCanonicalFile() ) );
} catch ( IOException ioe ) {
// this should never happen, but if it does return false...
return false;
}
}
/** This method returns the name of the Dynamo product that is
* installed. Because there is no guaranteed way to determine the
* installed product this method makes a best-guess. If the
* version is less than 5.5 then the method skips down from DCS, to
* DPS, etc. until it finds a product that exists. If the version
* 5.5, 5.6, or 5.6.1 then this method just returns 'AppDAP' since
* that is the only Dynamo product we have for those versions.
* Likewise, if the version is NOT anything between 4 and 5.6, then
* we return 'ATG' since that is the only version we have for
* copper, etc. If the method can't determine a version it returns
* UNKNOWN_INFO
*/
public static String getDynamoProductName()
{
AppModule module = getAtgDynamoModule();
if ( module == null ) return UNKNOWN_INFO;
String version = getAtgVersion(module);
if ( version == null ) {
return UNKNOWN_INFO;
} else if ( version.startsWith("5.5") || version.startsWith("5.6") ) {
// this is an AppDAP build of 5.5, 5.6, or 5.6.1
return "AppDAP";
} else if ( ! version.startsWith("4") && ! version.startsWith("5.0") && ! version.startsWith("5.1") ) {
// assume this is an ATG build from version 6.x
// TODO: Bug 78552 was opened to add a MANIFEST entry containing
// the product name so we don't have to guess at it.
return "ATG";
} else {
return UNKNOWN_INFO;
}
}
/** Returns information about the ATG Dynamo product being used.
* does not include information about the app server that may be in
* use. returns null if Dynamo is not running.
**/
public static String getDynamoProductInfo()
{
StringBuffer sb = new StringBuffer();
AppModule dynamo = getAtgDynamoModule();
if ( dynamo == null ) return null;
sb.append( getDynamoProductName() + " version " + getAtgVersion(dynamo) );
String build = getAtgBuildNumber(dynamo);
if ( ! build.equals(UNKNOWN_INFO) ) sb.append( " build " + build);
String patch_version = getAtgPatchVersion(dynamo);
String patch_build = getAtgPatchBuildNumber(dynamo);
if ( ! (patch_version == null) && ! patch_version.equals(UNKNOWN_INFO) )
sb.append( " with patch " + patch_version + " build " + patch_build );
return sb.toString();
}
/** Returns a summary of information about the App Server product
* being used.
*/
public static String getAppServerProductInfo() {
StringBuffer sb = new StringBuffer();
sb.append(getAppServerProductName() + " version " + getAppServerVersion());
String build = getAppServerBuildNumber();
if ( ! build.equals(UNKNOWN_INFO) ) sb.append( " build " + build);
String patch_version = getAppServerPatchVersion();
String patch_build = getAppServerPatchBuildNumber();
if ( ! (patch_version == null) && ! patch_version.equals(UNKNOWN_INFO) )
sb.append( " with patch " + patch_version + " build " + patch_build );
return sb.toString();
}
/** returns the java version that Dynamo is using
*
* @return String version of java Dynamo is using
*/
public static String getJavaVersion() {
return System.getProperty( JAVA_VERSION );
}
/** returns the java build version (java.version) that Dynamo is using
*
* @return String build version of java Dynamo is using
*/
public static String getJavaBuildVersion() {
return System.getProperty( JAVA_BUILD_VERSION );
}
/** returns detailed version information about the jdk being used */
public static String getJavaVersionDetails() {
return TestUtils.getJavaInfo() + " - " + TestUtils.getJavaVersion();
}
/** returns info about the java build that Dynamo is using
*
* @return String info about java build Dynamo is using
*/
public static String getJavaInfo() {
return System.getProperty( JAVA_VAR );
}
/** returns the type of compiler that Dynamo is using
*
* @return String compiler Dynamo is using
*/
public static String getCompilerType() {
return System.getProperty( COMPILER_VAR );
}
/** returns the type of Operating System that Dynamo is running on
*/
public static String getOperatingSystemType() {
return System.getProperty( OS_VAR )
+ " version " + System.getProperty( OS_VERSION_VAR );
}
/** returns the hostname of the machine that Dynamo is running on
*/
public static String getHostname() {
try {
InetAddress address = InetAddress.getLocalHost();
return address.getHostName();
} catch (UnknownHostException uhe) {}
return "unknown";
}
/** returns the name of the app server that dynamo is using */
public static String getAppServerType() {
if ( ServletUtil.isWebLogic() ) return APP_SERVER_BEA;
else if ( ServletUtil.isWebSphere() ) return APP_SERVER_IBM;
else if ( ServletUtil.isDynamoJ2EEServer() ) return APP_SERVER_DAS;
else if ( isGenericAppServer() ) return APP_SERVER_TOMCAT;
else return System.getProperty( APP_SERVER );
}
/** Returns true if Dynamo is running on a 'generic' (aka Tomcat)
* j2ee appserver; false otherwise.
* ServletUtil.isGenericJ2EEServer() method call does not exist in
* early Dynamo versions, so use reflection to invoke it. As of
* ATG 7x, isGenericJ2EEServer() really means "are we running on
* JBOSS" - I'm not sure whether we intend to differentiate between
* JBOSS and other 'generic' Tomcat app servers.
*/
public static boolean isGenericAppServer() {
try {
ServletUtil.class.newInstance();
return ((Boolean) invokeMethod(dynamoEnv(), "isGenericJ2EEServer", null, null, null)).booleanValue();
} catch (Throwable t) {}
return false;
}
/** returns the WAS home directory if running on WAS. otherwise,
* returns null */
public static String getWasHomeDir() {
return System.getProperty( "was.install.root" );
}
/** returns the WAS version number. if not running against WAS, or
* if the {WAS.install.root}/properties/version/BASE.product file
* can not be found, or if an error occurs parsing the file then
* returns UNKNOWN_INFO.
*/
public static String getWasVersion() {
String version = null;
try {
// WAS 5
File f = new File( getWasHomeDir(), "properties/version/BASE.product" );
// WAS 6
if (!f.exists())
f = new File( getWasHomeDir(),"properties/version/WAS.product" );
String[] children1 = { "version" };
List<Node> nodes1 = XmlUtils.getNodes(f, false, children1);
if (nodes1 != null ) {
Iterator<Node> iter1 = nodes1.iterator();
while (iter1.hasNext()) {
Node n1 = iter1.next();
version = XmlUtils.getNodeTextValue(n1);
}
}
} catch (Throwable e) {}
if ( version != null ) return version;
else return UNKNOWN_INFO;
}
/** returns the full file path of specified was log if
* getWasHomeDir() is not null. otherwise returns null. */
private static File getWasLogFile( String pServerName, String pLogName )
{
if ( getWasHomeDir() == null ) return null;
else return new File( getWasHomeDir(), "logs" + File.separator + pServerName + File.separator + pLogName );
}
private static String mWasSystemOutLogFile = null;
/** Specifies the log file to return when asked for the WAS
* 'SystemOut.log' file. if this value is null we attempt to
* calculate a default location */
public void setWasSystemOutLogFile( String pFile ) {
mWasSystemOutLogFile = pFile;
}
/** returns the expected location of the WAS 'SystemOut.log' file if
* running on WAS. otherwise returns null.*/
public static String getWasSystemOutLogFile() {
if ( getWasHomeDir() == null ) return null;
else if (mWasSystemOutLogFile != null
&& mWasSystemOutLogFile.trim().length() > 0)
return mWasSystemOutLogFile.trim();
else {
File f = getWasLogFile(ServletUtil.getWebsphereServerName(),"SystemOut.log");
if (f == null || ! f.exists())
f = getWasLogFile( "server1", "SystemOut.log" );
if ( f != null ) return f.getAbsolutePath();
}
return null;
}
private static String mWasSystemErrLogFile = null;
/** Specifies the log file to return when asked for the WAS
* 'SystemErr.log' file. if this value is null we attempt to
* calculate a default location */
public void setWasSystemErrLogFile( String pFile ) {
mWasSystemErrLogFile = pFile;
}
/** returns the expected location of the WAS 'SystemErr.log' file if
* running on WAS. otherwise returns null.*/
public static String getWasSystemErrLogFile() {
if ( getWasHomeDir() == null ) return null;
else if (mWasSystemErrLogFile != null
&& mWasSystemErrLogFile.trim().length() > 0)
return mWasSystemErrLogFile.trim();
else {
File f = getWasLogFile(ServletUtil.getWebsphereServerName(),"SystemErr.log");
if ( f == null || ! f.exists() )
f = getWasLogFile( "server1", "SystemErr.log" );
if ( f != null ) return f.getAbsolutePath();
}
return null;
}
/** returns the BEA home directory if running on BEA. otherwise,
* returns null */
public static String getBeaHomeDir() {
String homedir = System.getProperty( "bea.home" );
if ( homedir != null ) return homedir;
// sometimes (like on bea 8) 'bea.home' is not specified, so try
// to determine bea.home base on another property...
String startfile = System.getProperty( "java.security.policy" );
if ( startfile != null ) {
// the policy file is (hopefully) always located at a location like:
// /root/to/bea/<weblogic>/server/lib/weblogic.policy
// so we basically want to go up four levels from there...
homedir = atg.core.io.FileUtils.getParent( startfile );
// should now be in /root/to/bea/<weblogic>/server/lib
homedir = atg.core.io.FileUtils.getParent( homedir );
// should now be in /root/to/bea/<weblogic>/server
homedir = atg.core.io.FileUtils.getParent( homedir );
// should now be in /root/to/bea/<weblogic>
homedir = atg.core.io.FileUtils.getParent( homedir );
// should now be in /root/to/bea
}
return homedir;
}
private static String mBeaMyServerLogFile = null;
/** Specifies the log file to return when asked for the BEA
* 'myserver.log' file. if this value is null then a default value
* will be calculated. */
public static void setBeaMyServerLogFile( String pFile ) {
mBeaMyServerLogFile = pFile;
}
/** returns the expected location of the BEA 'myserver.log' file if
* running on BEA. otherwise returns null.*/
public static String getBeaMyServerLogFile() {
if ( getBeaHomeDir() == null ) return null;
else if (mBeaMyServerLogFile != null
&& mBeaMyServerLogFile.trim().length() > 0 )
return mBeaMyServerLogFile.trim();
else {
// try this default location....
String name = "user_projects" + File.separator +
"mydomain" + File.separator +
"myserver" + File.separator +
"myserver.log";
File log = new File( getBeaHomeDir(), name );
if ( log.exists() ) {
return log.getAbsolutePath();
} else {
// the default didn't work (as we shouldn't always expect it
// to) so try this location... 'user.dir' typically points to
// the domain dir: /path/to/bea/user_projects/mydomain
// 'weblogic.Name' should be like : myserver
name = System.getProperty( "user.dir" ) + File.separator +
System.getProperty( "weblogic.Name" ) + File.separator +
System.getProperty( "weblogic.Name" ) + ".log";
log = new File( name );
if ( log.exists() ) return log.getAbsolutePath();
}
}
return null;
}
/** returns the BEA version number. if not running against BEA, or if
* the {BEA_HOME}/registry.xml file can not be found, or if an error occurs
* parsing the file then returns UNKNOWN_INFO.
*/
public static String getBeaVersion()
{
String version = null;
try {
File f = new File( new File( getBeaHomeDir() ), "registry.xml" );
String[] children = { "host", "product", "release" };
List<Node> nodes = XmlUtils.getNodes(f, false, children);
if ( nodes != null ) {
Iterator<Node> iter = nodes.iterator();
// I expect there to only be one <host><product><release> node
// so this iteration should really just loop over one node.
while ( iter.hasNext() ) {
Node n = iter.next();
version = XmlUtils.getAttribute(n,"level","0") + "." +
XmlUtils.getAttribute(n,"ServicePackLevel","0") + "." +
XmlUtils.getAttribute(n,"PatchLevel","0");
}
}
} catch (Throwable e) {
}
if ( version != null ) return version;
else return UNKNOWN_INFO;
}
// ---------------- JBOSS Utility Methods --------------------------
// NOTE: Available JBoss System property names can be found in class
// org.jboss.system.server.ServerConfig
/** Returns the JBOSS installation home directory, if Dynamo is
* running on JBOSS. Otherwise returns null. */
public static File getJBossHomeDir() {
String dir = System.getProperty("jboss.home.dir");
if ( dir == null ) return null;
else return new File(dir);
}
/** Returns the JBOSS server home directory, if Dynamo is running on
* JBOSS. Otherwise returns null. */
public static File getJBossServerHomeDir() {
String dir = System.getProperty("jboss.server.home.dir");
if ( dir == null ) return null;
else return new File(dir);
}
/** Returns the JBOSS server name, if Dynamo is running on JBOSS.
* Otherwise returns null. */
public static String getJBossServerName() {
return System.getProperty("jboss.server.name");
}
/** Returns the path to the JBOSS server log file, if it can be
* found. Otherwise returns null */
public static String getJBossServerLog() {
try {
File log = new File( getJBossServerHomeDir(), "log/server.log" );
if ( log.exists() ) return log.getAbsolutePath();
} catch ( Throwable t ) {}
return null;
}
/** Returns the version of JBOSS being used, if it can be
* determined. Otherwise returns UNKNOWN_INFO. This method
* expects to find a 'jar-versions.xml' file in the JBoss home
* directory. It searches for the <jar> element whose 'name'
* attribute is "jboss.jar", and determines the version based on
* the value of the 'implVersion' attribute.
**/
public static String getJBossVersion() {
try {
File versionFile = new File( getJBossHomeDir(), "jar-versions.xml");
if (!versionFile.exists()) {
log("jar-versions.xml file does not exist; "
+ "unable to determine version info");
return UNKNOWN_INFO;
}
String[] children = { "jar" };
Iterator<Node> nodes = XmlUtils.getNodes(versionFile,false,children).iterator();
while ( nodes.hasNext() ) {
try {
Node node = nodes.next();
String name = node.getAttributes().getNamedItem("name").getNodeValue();
log("Checking node: " + name);
if ( name.equals("jboss.jar") ) {
String ver = node.getAttributes().getNamedItem("implVersion").getNodeValue().trim();
log("JBOSS version string: " + ver);
// implVersion is typically something like
// "4.0.1sp1 (build: CVSTag=JBoss_4_0_1_SP1 date=200502160314)"
// so, strip off the build information since we don't care about it
int idx = ver.indexOf(" (build:");
if ( idx != -1 ) ver = ver.substring(0,idx).trim();
return ver;
}
} catch (Throwable ti) {}
}
} catch (Throwable t) {}
return UNKNOWN_INFO;
}
private static atg.service.dynamo.Configuration DYN_CONFIG = null;
/** returns the Configuration component being used by Dynamo */
public static atg.service.dynamo.Configuration getDynamoConfiguration() {
if ( DYN_CONFIG == null ) {
try {
DYN_CONFIG = (atg.service.dynamo.Configuration) Nucleus.getGlobalNucleus().resolveName( CONFIGURATION_COMPONENT );
} catch (Throwable t) {}
}
return DYN_CONFIG;
}
/** returns the session limit of the specified license component
* @param String the component name of the license in question
* @param boolean true if Nucleus should attempt to create the license
* component if it does not exist
* @return int the session limit for the license. 0 if the license does not
* resolve.
**/
public static int getSessionLimit( String pLicense, boolean pResolve )
{
return -1;
}
// ==================== EMAIL ======================
/** This method is used to send an email message and allows the user
* to specify the return address.
* @return boolean true if the mail was sent successfully; otherwise false.
*/
public static boolean sendEmailWithReturn(String pAddress, String pMsg,
String pSubject,
String pBodyEncoding,
String pReturnAddress )
{
try {
// create a Message with the given From and Subject
Message msg = MimeMessageUtils.createMessage( pReturnAddress, pSubject);
// set the To recipient
MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
// set the message content: multipart message + attachment
if ( pBodyEncoding == null || pBodyEncoding.trim().length() == 0 )
pBodyEncoding = "text/plain";
ContentPart[] content =
{ new ContentPart( pMsg, pBodyEncoding) };
MimeMessageUtils.setContent(msg, content);
// create the email event
EmailEvent em = new EmailEvent(msg);
// now send the event
SMTPEmailSender sender = new SMTPEmailSender();
sender.setEmailHandlerHostName( MAILHOST );
sender.sendEmailEvent( em );
} catch (Exception e) {
log.info("Caught exception sending email: " + e.toString() );
return false;
}
return true;
}
/** This method is used to send an email message; returns true if
* everything went ok; otherwise, returns false
*/
public static boolean sendEmail(String pAddress, String pMsg,
String pSubject, String pBodyEncoding)
{
return sendEmailWithReturn(pAddress,pMsg,pSubject,pBodyEncoding,pAddress);
}
/** This method is used to send an email message; returns true if
* everything went ok; otherwise, returns false
*/
public static boolean sendEmail(String pAddress, String pMsg,
String pSubject)
{
return sendEmail( pAddress, pMsg, pSubject, "text/plain" );
}
/** This method is used to send the same email message to a vector
* of recipients
*/
public static void sendEmails(List<String> pAddresses, String pMsg,
String pSubject, String pBodyEncoding )
{
// make sure addresses are valid
if ( pAddresses == null ||
pAddresses.size() <= 0 )
return;
// send emails
Iterator<String> addresses = pAddresses.iterator();
String address = null;
while ( addresses.hasNext() ) {
try {
address = addresses.next();
if ( address != null && address.trim().length() > 0 )
sendEmail(address.trim(),pMsg,pSubject,null,null,null,pBodyEncoding);
} catch (Exception e) {}
}
}
/** This method is used to send the same email message to a vector
* of recipients. It encodes the message body as "text/plain".
*/
public static void sendEmails(List<String> pAddresses, String pMsg,
String pSubject )
{
sendEmails( pAddresses, pMsg, pSubject, "text/plain" );
}
/** This method is used to send an email message that contains
* several attachments. This method is specifically designed to
* accept a map of java.lang.Strings as content parts instead of
* java.io.Files. The key in the Map should be a String
* representing the name that you would like to show for the
* attached file. The value in the Map should be a String
* representing the contents of the attachment.
*/
public static void sendEmail(String pAddress, String pMsg, String pSubject,
Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments,
File[] pFiles, String pBodyEncoding )
{
try {
// make sure addresses are valid
if ( pAddress == null ||
pAddress.trim().length() == 0 )
return;
// create a Message with the given From and Subject
Message msg = MimeMessageUtils.createMessage( pAddress, pSubject);
// set the To recipient
MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
// create the MultiPart used to hold everything
Multipart mp = new MimeMultipart();
// set the message content: multipart message + attachment
BodyPart guts = new MimeBodyPart();
if ( pBodyEncoding == null || pBodyEncoding.trim().length() == 0 )
pBodyEncoding = "text/plain";
guts.setContent( pMsg, pBodyEncoding );
mp.addBodyPart( guts );
// add the text attachments
if ( pTextAttachments != null ) {
Iterator<String> textkeys = pTextAttachments.keySet().iterator();
while ( textkeys.hasNext() ) {
String key = textkeys.next();
Object val = pTextAttachments.get( key );
if ( val != null ) {
MimeBodyPart part = new MimeBodyPart();
part.setContent( val.toString(), "text/plain" );
part.setDisposition( MimeBodyPart.ATTACHMENT );
part.setDescription( key );
part.setFileName( key );
mp.addBodyPart( part );
}
}
}
// add the html attachments
if ( pHTMLAttachments != null ) {
Iterator<String> htmlkeys = pHTMLAttachments.keySet().iterator();
while ( htmlkeys.hasNext() ) {
String key = htmlkeys.next();
Object val = pHTMLAttachments.get( key );
if ( val != null ) {
MimeBodyPart part = new MimeBodyPart();
part.setContent( val.toString(), "text/html" );
part.setDisposition( MimeBodyPart.ATTACHMENT );
part.setDescription( key );
part.setFileName( key );
mp.addBodyPart( part );
}
}
}
// add the File attachments
if ( pFiles != null ) {
for ( int i=0; i<pFiles.length; i++ ) {
MimeBodyPart part = new MimeBodyPart();
part.setDataHandler(new DataHandler(new FileDataSource(pFiles[i])));
part.setFileName( pFiles[i].getName() );
mp.addBodyPart( part );
}
}
msg.setContent( mp );
// create the email event
EmailEvent em = new EmailEvent(msg);
// now send the event
SMTPEmailSender sender = new SMTPEmailSender();
sender.setEmailHandlerHostName( MAILHOST );
sender.sendEmailEvent( em );
} catch (Exception e) {
log.info("Caught exception sending email: " + e.toString() );
e.printStackTrace();
}
}
/** This method is used to send an email message that contains
* several attachments. This method is specifically designed to
* accept a map of java.lang.Strings as content parts instead of
* java.io.Files. The key in the Map should be a String
* representing the name that you would like to show for the
* attached file. The value in the Map should be a String
* representing the contents of the attachment. If you wish to
* attach java.io.Files, use the static methods found in
* atg.service.email.MimeMessageUtils.
*/
public static void sendEmail(String pAddress, String pMsg, String pSubject,
Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments,
String pBodyEncoding )
{
sendEmail( pAddress, pMsg, pSubject, pTextAttachments, pHTMLAttachments, null, pBodyEncoding );
}
/** This method is used to send an email message that contains
* several attachments. This method is specifically designed to
* accept a map of java.lang.Strings as content parts instead of
* java.io.Files. The key in the Map should be a String
* representing the name that you would like to show for the
* attached file. The value in the Map should be a String
* representing the contents of the attachment. If you wish to
* attach java.io.Files, use the static methods found in
* atg.service.email.MimeMessageUtils.
*/
public static void sendEmail( String pAddress, String pMsg, String pSubject,
Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments )
{
sendEmail( pAddress,pMsg,pSubject,pTextAttachments,pHTMLAttachments,"text/plain");
}
/** This method is used to send an email message that contains
* several attachments. This method is specifically designed to
* accept a map of java.lang.Strings as content parts instead of
* java.io.Files. The key in the Map should be a String
* representing the name that you would like to show for the
* attached file. The value in the Map should be a String
* representing the contents of the attachment.
*/
public static void sendEmails(List<String> pAddresses, String pMsg,
String pSubject, Map<String, Object> pTextAttachments,
Map<String, Object> pHTMLAttachments, File[] pFiles,
String pBodyEncoding )
{
// make sure addresses are valid
if ( pAddresses == null ||
pAddresses.size() <= 0 )
return;
// send emails
Iterator<String> addresses = pAddresses.iterator();
String address = null;
while ( addresses.hasNext() ) {
try {
address = addresses.next();
if ( address != null && address.trim().length() > 0 )
sendEmail(address.trim(), pMsg, pSubject, pTextAttachments,
pHTMLAttachments, pFiles, pBodyEncoding );
} catch (Exception e) {}
}
}
/** This method is used to send an email message that contains
* several attachments to multiple recipients. This method is
* specifically designed to accept a map of java.lang.Strings as
* content parts instead of java.io.Files. The key in the Map
* should be a String representing the name that you would like to
* show for the attached file. The value in the Map should be a
* String representing the contents of the attachment.
*/
public static void sendEmails(List<String> pAddresses, String pMsg,
String pSubject, Map<String, Object> pTextAttachments,
Map<String, Object> pHTMLAttachments, String pBodyEncoding )
{
sendEmails( pAddresses, pMsg, pSubject, pTextAttachments, pHTMLAttachments, null, pBodyEncoding );
}
/** This method is used to send an email message that contains
* several attachments to multiple recipients. The message will
* have it's main body part encoded as "text/plain". <br>This
* method is specifically designed to accept a map of
* java.lang.Strings as content parts instead of java.io.Files.
* The key in the Map should be a String representing the name that
* you would like to show for the attached file. The value in the
* Map should be a String representing the contents of the
* attachment. If you wish to attach java.io.Files, use the static
* methods found in atg.service.email.MimeMessageUtils.
*/
public static void sendEmails(List<String> pAddresses, String pMsg,
String pSubject, Map<String, Object> pTextAttachments,
Map<String, Object> pHTMLAttachments )
{
sendEmails(pAddresses,pMsg,pSubject,pTextAttachments,pHTMLAttachments,"text/plain");
}
// ======================== EXCEPTIONS =====================
/** this method returns a String representation of an Exception's stacktrace
*/
public static String getStackTrace( Throwable pException ) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream( bos );
pException.printStackTrace( ps );
ps.flush();
return bos.toString();
}
// ===================== URL ACCESS ========================
/** this method returns the contents of the page specified as the
* URL. the URL should be a fully qualified request string. for
* example, http://rygar.atg.com:8880/some/directory/page.jhtml
*
* If the boolean parameter is set to true then this method will
* throw an Exception if an error occurs; otherwise it will simply
* return the contents of the exception.
*
* @exception MalformedURLException if URL is malformed & pThrow is true
* @exception IOException if error happens while reading and pThrow is true
*/
public static String accessURL( String pUrl, boolean pThrow )
throws MalformedURLException, IOException
{
URL url = null;
StringBuffer results = new StringBuffer();
BufferedReader in = null;
InputStreamReader isr = null;
try {
url = new URL( pUrl );
isr = new InputStreamReader( url.openStream() );
in = new BufferedReader( isr );
String line = null;
while ( ( line = in.readLine() ) != null ) {
results.append( line + "\n" );
}
return results.toString();
} catch ( MalformedURLException e ) {
if ( pThrow )
throw e;
else
results.append( "\nEncountered an unexpected error while trying to retrieve the configuration info." +
"\nWhen the url " + url + " was requested, this error was received: \n" + getStackTrace( e ) + "\n" );
} catch ( IOException ioe ) {
if ( pThrow )
throw ioe;
else
results.append( "\nEncountered an unexpected error while trying to retrieve the configuration info." +
"\nWhen the url " + url + " was requested, this error was received: \n" + getStackTrace( ioe ) + "\n");
} finally {
if ( in != null ) {
try { in.close(); }
catch (Exception e) {}
}
if ( isr != null ) {
try { isr.close(); }
catch (Exception e) {}
}
}
return results.toString();
}
/** this method returns the contents of the page specified as the URL. the
* URL should be a fully qualified request string. for example,
* http://rygar.atg.com:8880/some/directory/page.jhtml
*
* Unlike it's sister method with the boolean parameter, this method will
* not throw an exception.
*/
public static String accessURL( String pUrl )
{
try {
return accessURL( pUrl, false );
} catch (Exception e) {
return "\nEncountered an unexpected error while trying to retrieve the configuration info." +
"\nWhen the url " + pUrl + " was requested, this error was received: \n" + getStackTrace( e ) + "\n";
}
}
// ==================== File IO ============================
/**
* Writes the byte array into the specified file.
*
* @param File pFile the file to write to
* @param byte[] the bytes to write
*
* @exception IOException if an error occurred opening or reading the file.
*/
public static void writeFileBytes(File pFile, byte[] pBytes)
throws IOException
{
if ( pBytes == null ) pBytes = new byte[0];
FileOutputStream fos = null;
try {
fos = new FileOutputStream( pFile );
fos.write( pBytes );
}
catch (IOException e) {
throw e;
}
finally {
try { if (fos != null) fos.close (); }
catch (IOException exc) {}
}
}
/** converts a delimiter separated String of file names into an
* array and expands all System property variables in the Strings.
* it does not check whether resolved file paths exist.
*
* @param String delimited string of files to be converted to array.
* @param String delimiter string used to separated files
* @return String[] array of expanded paths
* @exception Exception if files can't be resolved properly
*/
public static String[] convertFileArray( String pFiles, String pDelimiter )
throws Exception
{
return convertFileArray( pFiles, pDelimiter, null );
}
/** converts a delimiter separated String of file names into an array
* and expands all variables in the Strings. it does not check whether
* resolved file paths exist.
*
* @param String delimited string of files to be converted to array.
* @param String delimiter string used to separated files
* @param Properties optional primary mapping of key/value pairs to
* substitute into file paths whererever the syntax <tt>{...}</tt>
* is found. If parameter is null, or mapping not found, then
* System.getProperties() is checked.
* @return String[] array of expanded paths
* @exception Exception if files can't be resolved properly
*/
public static String[] convertFileArray(String pFiles, String pDelimiter,
Properties pPrimaryMapping )
throws Exception
{
if ( pDelimiter == null ) pDelimiter = "";
StringTokenizer st = new StringTokenizer( pFiles, pDelimiter );
List<String> files = new LinkedList<String>();
while ( st.hasMoreTokens() ) {
files.add( expand(st.nextToken(), pPrimaryMapping) );
}
return (String[]) files.toArray( new String[files.size()] );
}
/** expands all System property variables specified in the supplied
* String using curly braces syntax <tt>{...}</tt> and returns the
* resulting String.
*
* @param String the string to expand.
* @exception Exception if a System property resolves to null or if
* the enclosing braces are not properly matched.
*/
public static String expand( String pString )
throws Exception
{
return expand( pString, null );
}
/** expands all property variables specified in the supplied String
* using curly braces syntax <tt>{...}</tt> and returns the
* resulting String. Property names inside the curly braces can be
* either a simple String referring to a Java System property, such
* as "SystemProperty.X", or can be in AppModuleResource format,
* such as
* "appModuleResource?moduleID=MyModule&resource=my/resource/file".
*
* @param String the string to expand.
* @param Properties an optional primary key/value mapping to use
* for System property substitutions. If param is null, or if
* mapping not found, then System.getProperties().getProperty(xxx)
* is used.
* @return String the expanded string.
* @exception Exception if a System or AppModuleResource property
* resolves to null or if the enclosing braces are not properly
* matched.
*/
public static String expand( String pString, Properties pPrimaryMapping )
throws Exception
{
int idx = pString.indexOf("{");
while ( idx != -1 ) {
int end = pString.indexOf("}");
if ( end == -1 )
throw new Exception("Unclosed braces in String " + pString );
String pname = pString.substring(idx+1,end);
String prop = null;
if ( pPrimaryMapping != null ) prop = pPrimaryMapping.getProperty(pname);
if ( prop == null ) {
if ( pname.startsWith("appModuleResource?") )
prop = resolveAppModuleResourceReference(pname).getPath();
// atg.dynamo.root and atg.dynamo.home are resolved specially
// because of BigEar
else if ( pname.equals(ROOT_VAR) ) prop = getDynamoRootDir().getPath();
else if ( pname.equals(HOME_VAR) ) prop = getDynamoHomeDir().getPath();
else prop = System.getProperty(pname);
}
if ( prop == null )
throw new Exception("System property '"
+ pString.substring(idx+1,end)
+ "' is null. String " + pString
+ " can not be resolved.");
pString = pString.substring(0,idx) + prop + pString.substring(end+1);
idx = pString.indexOf("{");
}
return pString;
}
// ===================== atg dynamo info ===================================
/** product module corresponding to ATG Dynamo */
public static String ATGDYNAMO_PRODUCT_MODULE = "DPS";
/** specifies the name of the ATG Dynamo product module that will be
* loaded if Dynamo is being used. */
public static void setAtgDynamoProductModule( String pModule ) {
ATGDYNAMO_PRODUCT_MODULE = pModule;
}
/** returns the name of the ATG Dynamo product module that will be
* loaded if Dynamo is being used. */
public static String getAtgDynamoProductModule() {
return ATGDYNAMO_PRODUCT_MODULE;
}
/** returns an AppModule corresponding to the ATG Dynamo if that
* product is loaded. If it isn't loaded then returns null.
*/
public static AppModule getAtgDynamoModule()
{
// get all modules that were started with dynamo
Iterator<?> modules = getAppLauncher().getModules().iterator();
while ( modules.hasNext() ) {
AppModule module = (AppModule)modules.next();
if ( module.getName().equals( getAtgDynamoProductModule() ) )
return module;
}
return null;
}
// ==================== atg j2ee server info ==============================
/** product module corresponding to ATG's J2EE Server */
public static String ATGJ2EESERVER_PRODUCT_MODULE = "J2EEServer";
/** specifies the name of the ATG J2EE Server product module that
* will be loaded if ATG's J2EE Server is being used. */
public static void setAtgJ2eeServerProductModule( String pModule ) {
ATGJ2EESERVER_PRODUCT_MODULE = pModule;
}
/** returns the name of the ATG J2EE Server product module that will
* be loaded if ATG's J2EE Server is being used. */
public static String getAtgJ2eeServerProductModule() {
return ATGJ2EESERVER_PRODUCT_MODULE;
}
/** returns an AppModule corresponding to the ATG J2EE Server if
* that product is loaded. If it isn't loaded then returns null.
*/
public static AppModule getAtgJ2eeServerModule()
{
// get all modules that were started with dynamo
Iterator<?> modules = getAppLauncher().getModules().iterator();
while ( modules.hasNext() ) {
AppModule module = (AppModule)modules.next();
if ( module.getName().equals( getAtgJ2eeServerProductModule() ) )
return module;
}
return null;
}
// ==================== application info ============================
/** possible application product modules that may be installed */
public static String[] APPLICATION_PRODUCT_MODULES = {"ACA","ABTest","DCS-SO","CAF"};
/** specifies the names of possible application product modules that
* may be installed in Dyanmo. used to help report on which
* application modules are running. */
public void setApplicationProductModules( String[] pModules ) {
APPLICATION_PRODUCT_MODULES = pModules;
}
/** returns the names of possible application product modules that
* may be installed in Dyanmo. used to help report on which
* application modules are running. NOTE: This method should not
* be called. It is only provided so we can specify application
* modules in a .properties file. Java classes should call method
* getApplicationModules().*/
public String[] getApplicationProductModules() {
return APPLICATION_PRODUCT_MODULES;
}
/** returns an array of AppModule items corresponding to the
* currently running application products.
*/
public static AppModule[] getApplicationModules()
{
List<AppModule> apps = new LinkedList<AppModule>();
// get all modules that were started with dynamo
Iterator<?> modules = getAppLauncher().getModules().iterator();
while ( modules.hasNext() ) {
AppModule module = (AppModule)modules.next();
for ( int i=0; i<APPLICATION_PRODUCT_MODULES.length; i++ ) {
// in order to work around bug 80207, we allow a colon ":" in
// the specified module names. if a colon exists, the name
// before the colon is the name of the module that would be
// started if the application is running. the name after the
// colon is the module containing the MANIFEST.MF file with
// build info. if there is no colon, assume the two modules
// are the same.
int idx = APPLICATION_PRODUCT_MODULES[i].indexOf(":");
if ( idx == -1 ) {
// no colon...
if ((APPLICATION_PRODUCT_MODULES[i]).equals(module.getName()))
apps.add( module );
} else {
if (APPLICATION_PRODUCT_MODULES[i].substring(0,idx).equals(module.getName())) {
// NOTE: getAppLauncher().getModule(...) will return a
// module as long as it exists; the module does not need
// to be running.
try {
AppModule mod = getAppLauncher().getModule(APPLICATION_PRODUCT_MODULES[i].substring(idx+1));
log.info("\nMod: " + mod );
if ( mod != null ) apps.add( mod );
else throw new Exception(APPLICATION_PRODUCT_MODULES[i].substring(idx+1) + " not found.");
} catch (Exception ale) {
log.info("*** WARNING [atg.junit.nucleus.TestUtils] "
+ "Can not resolve module '"
+ APPLICATION_PRODUCT_MODULES[i].substring(idx+1)
+ "'. "
+ ale.getMessage() );
}
}
}
}
}
return (AppModule[]) apps.toArray( new AppModule[ apps.size() ] );
}
// =========== generic AppModule info retrieval methods ====================
private static AppLauncher mAppLauncher = null;
/** Returns the AppLauncher used to load this class. */
private static AppLauncher getAppLauncher()
{
if ( mAppLauncher == null )
mAppLauncher = AppLauncher.getAppLauncher( TestUtils.class );
return mAppLauncher;
}
/** Retrieves a File resource from a Dynamo Module. Note that the
* module does not need to be started, it simply has to be
* installed in the Dynamo. Returned file is <u>not</u> verified
* to exist.
*
* @param String pModuleName the name of the Dynamo module to look in. e.g. "SystemTests.JSPTest"
* @param String pResourceURI the URI of the File to get from the module. e.g. "mite.xml"
* @return File the requested file.
**/
public static File getModuleResourceFile(String pModuleName, String pResourceURI )
{
return getAppLauncher().getAppModuleManager().getResourceFile(pModuleName, pResourceURI);
}
/** Resolves an appModuleResource reference by parsing the string
* into its constituent ModuleID and ResourceURI.
*
* @param String pReference The AppModuleResource reference to resolve. Expected to be of format:
* <br><tt>appModuleResource?moduleID=<i>moduleID</i>&resourceURI=<i>some/URI</i></tt>
* @return File the referenced module resource.
* @exception IllegalArgumentException if the specified reference does not have the proper structure.
*/
public static File resolveAppModuleResourceReference( String pReference )
{
// there's probably a standard utility method in Dynamo to do this
// resolution, but i can't find it...
String moduleID = null;
String resourceURI = null;
String ref = pReference;
try {
int idx = ref.indexOf("moduleID="); // locate moduleID delimiter
if ( idx == -1 ) throw new Exception();
ref = ref.substring( idx + 9 ); // strip up to and including 'moduleID='
idx = ref.indexOf("&resourceURI="); // get index of resourceURI delimiter
moduleID = ref.substring( 0,idx ); // extract moduleID
resourceURI = ref.substring( idx + 13 ); // extract resourceURI
} catch (Throwable t) {
throw new IllegalArgumentException("Can not resolve appModuleReference. "
+ "Illegal reference syntax: "
+ pReference);
}
return getModuleResourceFile(moduleID, resourceURI);
}
/** Retrieves a piece of information from the MANIFEST of the
* supplied AppModule. Returns null if the specified information
* can't be found.
*/
public static String getManifestInfo( AppModule pModule, String pEntry)
{
return getManifestInfo( pModule.getManifest(), pEntry );
}
/**
* Logs a message using Nucleus.logInfo() if Nucleus is available.
* Otherwise it logs using log.info()
* @param pMessage
*/
public static void log (String pMessage) {
Nucleus n = Nucleus.getGlobalNucleus();
if (n != null)
n.logInfo(pMessage);
else
log.info(new java.util.Date() + ":" + pMessage);
}
/** Retrieves a piece of information from the specified Manifest file.
* Returns null if the specified information can't be found.
*/
public static String getManifestInfo( Manifest pManifest, String pEntry)
{
// if manifest or entry key is null return null...
if ( pManifest == null || pEntry == null ) return null;
if ( pManifest.getMainAttributes() == null ) return null;
else return pManifest.getMainAttributes().getValue( pEntry );
}
/** Returns the ATG product version ("ATG-Version") of the specified module.
* Returns UNKNOWN_INFO if the product version can't be determined.
**/
public static String getAtgVersion(AppModule pModule) {
String version = getManifestInfo(pModule, "ATG-Version");
if ( version != null ) return version;
else return UNKNOWN_INFO;
}
/** Returns the ATG product build number ("ATG-Build") of the
* specified module. Returns UNKNOWN_INFO if the build number
* can't be determined.
**/
public static String getAtgBuildNumber(AppModule pModule) {
String build = getManifestInfo(pModule, "ATG-Build");
if ( build != null ) return build;
else return UNKNOWN_INFO;
}
/** Returns the ATG patch version ("ATG-Patch-Version") of the
* specified module. Returns null if the module's version can be
* determined, but a patch version can't. Returns UNKNOWN_INFO if
* neither the product or patch version can be determined.
**/
public static String getAtgPatchVersion(AppModule pModule) {
String version = getManifestInfo(pModule, "ATG-Patch-Version");
if ( version != null ) return version;
else if (getAtgVersion(pModule).equals(UNKNOWN_INFO)) return UNKNOWN_INFO;
else return null;
}
/** Returns the ATG patch build number ("ATG-Patch-Build") of the
* specified module. Returns null if the module's build number can
* be determined, but a patch build number can't. Returns
* UNKNOWN_INFO if neither the product or patch build number can be
* determined.
**/
public static String getAtgPatchBuildNumber(AppModule pModule) {
String build = getManifestInfo(pModule, "ATG-Patch-Build");
if ( build != null ) return build;
else if (getAtgBuildNumber(pModule).equals(UNKNOWN_INFO))
return UNKNOWN_INFO;
else return null;
}
/** Returns the ATG full product version ("ATG-Version-Full") of the
* specified module. Returns UNKNOWN_INFO if the full product
* version can't be determined.
**/
public static String getAtgFullVersion(AppModule pModule) {
String version = getManifestInfo(pModule, "ATG-Version-Full");
if ( version != null ) return version;
else return UNKNOWN_INFO;
}
// ==================== Dynamo Environment Information =====================
// some methods called on DynamoEnv are not available in older
// versions of the class, so use reflection to maintain backward
// compatibility.
private static DynamoEnv mDynamoEnv = null;
private static DynamoEnv dynamoEnv() {
if ( mDynamoEnv == null ) {
try { mDynamoEnv = (DynamoEnv) DynamoEnv.class.newInstance(); }
catch (Throwable t) {}
}
return mDynamoEnv;
}
/** Returns true if Dynamo is running as BigEar; otherwise returns false. */
public static boolean isBigEar()
{
Boolean isBigEar = (Boolean) invokeMethod(dynamoEnv(), "isBigEar",
null, null, Boolean.FALSE );
return isBigEar.booleanValue();
}
/** Returns true if Dynamo is running as BigEar in standalone mode;
* otherwise returns false. */
public static boolean isBigEarStandalone()
{
Boolean isStandalone = (Boolean) invokeMethod(dynamoEnv(),
"getStandaloneMode",
null, null, Boolean.FALSE );
return isStandalone.booleanValue();
}
/** Returns true is Dynamo is running with liveconfig enabled;
* otherwise returns false. */
public static boolean isLiveconfig()
{
// 'isLiveconfig' is a new method in Koko (pr 88105). try it, but
// if that doesn't work try the 'getProperty' method that was used
// for ATG 7.0. finally, if that doesn't work just examine System
// properties as a last check.
Boolean isliveconfig = (Boolean) invokeMethod(dynamoEnv(),
"isLiveconfig",
null, null, null);
if ( isliveconfig == null ) {
// that method didn't work, so try this method - which should
// work in ATG 7
String[] args = { "atg.dynamo.liveconfig" };
String propval = (String) invokeMethod(dynamoEnv(),
"getProperty", new Class[]{ String.class }, args, null);
if ( propval != null ) {
isliveconfig = Boolean.valueOf("on".equalsIgnoreCase(propval));
} else {
isliveconfig = Boolean.valueOf("on".equalsIgnoreCase( System.getProperty("atg.dynamo.liveconfig") ));
}
}
if ( isliveconfig != null ) return isliveconfig.booleanValue();
else return false;
}
public static Object invokeMethod(Object pObj, String pMethodName,
Class<?>[] pSignature, Object[] pParams,
Object pDefault )
{
Object returnval = null;
try {
Method meth = pObj.getClass().getMethod( pMethodName, pSignature );
returnval = meth.invoke( pObj, pParams );
//if ( isLoggingDebug() ) logDebug("Method '" + pMethodName + "'
//invoked - return value: " + returnval);
} catch (Throwable t) {
//if ( isLoggingDebug() ) logDebug("Method '" + pMethodName + "'
//could not be invoked.", t);
returnval = pDefault;
}
return returnval;
}
} // end of class