EMMA Coverage Report (generated Tue Nov 24 15:49:41 EST 2009)
[all classes][atg.junit.nucleus]

COVERAGE SUMMARY FOR SOURCE FILE [TestUtils.java]

nameclass, %method, %block, %line, %
TestUtils.java0%   (0/1)0%   (0/97)0%   (0/2234)0%   (0/526)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class TestUtils0%   (0/1)0%   (0/97)0%   (0/2234)0%   (0/526)
<static initializer> 0%   (0/1)0%   (0/50)0%   (0/15)
TestUtils (): void 0%   (0/1)0%   (0/3)0%   (0/1)
accessURL (String): String 0%   (0/1)0%   (0/21)0%   (0/3)
accessURL (String, boolean): String 0%   (0/1)0%   (0/152)0%   (0/26)
convertFileArray (String, String): String [] 0%   (0/1)0%   (0/5)0%   (0/1)
convertFileArray (String, String, Properties): String [] 0%   (0/1)0%   (0/33)0%   (0/6)
dynamoEnv (): DynamoEnv 0%   (0/1)0%   (0/10)0%   (0/4)
expand (String): String 0%   (0/1)0%   (0/4)0%   (0/1)
expand (String, Properties): String 0%   (0/1)0%   (0/121)0%   (0/20)
getAppLauncher (): AppLauncher 0%   (0/1)0%   (0/7)0%   (0/3)
getAppServerBuildNumber (): String 0%   (0/1)0%   (0/11)0%   (0/4)
getAppServerPatchBuildNumber (): String 0%   (0/1)0%   (0/11)0%   (0/4)
getAppServerPatchVersion (): String 0%   (0/1)0%   (0/11)0%   (0/4)
getAppServerProductInfo (): String 0%   (0/1)0%   (0/62)0%   (0/9)
getAppServerProductName (): String 0%   (0/1)0%   (0/8)0%   (0/2)
getAppServerType (): String 0%   (0/1)0%   (0/19)0%   (0/5)
getAppServerVendor (): String 0%   (0/1)0%   (0/28)0%   (0/10)
getAppServerVersion (): String 0%   (0/1)0%   (0/29)0%   (0/10)
getApplicationModules (): AppModule [] 0%   (0/1)0%   (0/131)0%   (0/19)
getApplicationProductModules (): String [] 0%   (0/1)0%   (0/2)0%   (0/1)
getAtgBuildNumber (AppModule): String 0%   (0/1)0%   (0/10)0%   (0/3)
getAtgDynamoModule (): AppModule 0%   (0/1)0%   (0/21)0%   (0/7)
getAtgDynamoProductModule (): String 0%   (0/1)0%   (0/2)0%   (0/1)
getAtgFullVersion (AppModule): String 0%   (0/1)0%   (0/10)0%   (0/3)
getAtgJ2eeServerInstallDir (): File 0%   (0/1)0%   (0/9)0%   (0/2)
getAtgJ2eeServerModule (): AppModule 0%   (0/1)0%   (0/21)0%   (0/7)
getAtgJ2eeServerProductModule (): String 0%   (0/1)0%   (0/2)0%   (0/1)
getAtgJ2eeServerProductName (): String 0%   (0/1)0%   (0/6)0%   (0/2)
getAtgPatchBuildNumber (AppModule): String 0%   (0/1)0%   (0/17)0%   (0/5)
getAtgPatchVersion (AppModule): String 0%   (0/1)0%   (0/17)0%   (0/4)
getAtgVersion (AppModule): String 0%   (0/1)0%   (0/10)0%   (0/3)
getBeaHomeDir (): String 0%   (0/1)0%   (0/26)0%   (0/9)
getBeaMyServerLogFile (): String 0%   (0/1)0%   (0/77)0%   (0/11)
getBeaVersion (): String 0%   (0/1)0%   (0/76)0%   (0/14)
getCompilerType (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getDustUsername (): String 0%   (0/1)0%   (0/11)0%   (0/3)
getDustVersion (): int 0%   (0/1)0%   (0/2)0%   (0/1)
getDynamoConfiguration (): Configuration 0%   (0/1)0%   (0/11)0%   (0/4)
getDynamoHomeDir (): File 0%   (0/1)0%   (0/21)0%   (0/7)
getDynamoInstallDir (): File 0%   (0/1)0%   (0/2)0%   (0/1)
getDynamoProductInfo (): String 0%   (0/1)0%   (0/72)0%   (0/11)
getDynamoProductName (): String 0%   (0/1)0%   (0/39)0%   (0/10)
getDynamoRootDir (): File 0%   (0/1)0%   (0/19)0%   (0/7)
getHostname (): String 0%   (0/1)0%   (0/8)0%   (0/4)
getJBossHomeDir (): File 0%   (0/1)0%   (0/12)0%   (0/3)
getJBossServerHomeDir (): File 0%   (0/1)0%   (0/12)0%   (0/3)
getJBossServerLog (): String 0%   (0/1)0%   (0/16)0%   (0/4)
getJBossServerName (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJBossVersion (): String 0%   (0/1)0%   (0/90)0%   (0/19)
getJavaBuildVersion (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJavaInfo (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJavaVersion (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getJavaVersionDetails (): String 0%   (0/1)0%   (0/11)0%   (0/1)
getManifestInfo (AppModule, String): String 0%   (0/1)0%   (0/5)0%   (0/1)
getManifestInfo (Manifest, String): String 0%   (0/1)0%   (0/16)0%   (0/3)
getModuleResourceFile (String, String): File 0%   (0/1)0%   (0/6)0%   (0/1)
getOperatingSystemType (): String 0%   (0/1)0%   (0/13)0%   (0/1)
getSessionLimit (String, boolean): int 0%   (0/1)0%   (0/17)0%   (0/4)
getStackTrace (Throwable): String 0%   (0/1)0%   (0/17)0%   (0/5)
getTsmTestrun (): String 0%   (0/1)0%   (0/2)0%   (0/1)
getWasHomeDir (): String 0%   (0/1)0%   (0/3)0%   (0/1)
getWasLogFile (String, String): File 0%   (0/1)0%   (0/23)0%   (0/2)
getWasSystemErrLogFile (): String 0%   (0/1)0%   (0/33)0%   (0/8)
getWasSystemOutLogFile (): String 0%   (0/1)0%   (0/33)0%   (0/8)
getWasVersion (): String 0%   (0/1)0%   (0/53)0%   (0/15)
invokeMethod (Object, String, Class [], Object [], Object): Object 0%   (0/1)0%   (0/19)0%   (0/7)
isBigEar (): boolean 0%   (0/1)0%   (0/11)0%   (0/2)
isBigEarStandalone (): boolean 0%   (0/1)0%   (0/11)0%   (0/2)
isDynamoInstalled (): boolean 0%   (0/1)0%   (0/17)0%   (0/4)
isGenericAppServer (): boolean 0%   (0/1)0%   (0/15)0%   (0/4)
isLiveconfig (): boolean 0%   (0/1)0%   (0/51)0%   (0/9)
log (String): void 0%   (0/1)0%   (0/23)0%   (0/5)
resolveAppModuleResourceReference (String): File 0%   (0/1)0%   (0/56)0%   (0/13)
sendEmail (String, String, String): boolean 0%   (0/1)0%   (0/6)0%   (0/1)
sendEmail (String, String, String, Map, Map): void 0%   (0/1)0%   (0/8)0%   (0/2)
sendEmail (String, String, String, Map, Map, File [], String): void 0%   (0/1)0%   (0/188)0%   (0/52)
sendEmail (String, String, String, Map, Map, String): void 0%   (0/1)0%   (0/9)0%   (0/2)
sendEmail (String, String, String, String): boolean 0%   (0/1)0%   (0/7)0%   (0/1)
sendEmailWithReturn (String, String, String, String, String): boolean 0%   (0/1)0%   (0/62)0%   (0/15)
sendEmails (List, String, String): void 0%   (0/1)0%   (0/6)0%   (0/2)
sendEmails (List, String, String, Map, Map): void 0%   (0/1)0%   (0/8)0%   (0/2)
sendEmails (List, String, String, Map, Map, File [], String): void 0%   (0/1)0%   (0/37)0%   (0/10)
sendEmails (List, String, String, Map, Map, String): void 0%   (0/1)0%   (0/9)0%   (0/2)
sendEmails (List, String, String, String): void 0%   (0/1)0%   (0/37)0%   (0/10)
setApplicationProductModules (String []): void 0%   (0/1)0%   (0/3)0%   (0/2)
setAtgDynamoProductModule (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
setAtgJ2eeServerProductModule (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
setBeaMyServerLogFile (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
setDustUsername (String): void 0%   (0/1)0%   (0/3)0%   (0/1)
setDustVersion (int): void 0%   (0/1)0%   (0/3)0%   (0/1)
setDynamoInstallDir (File): void 0%   (0/1)0%   (0/3)0%   (0/1)
setP4Synctime (): String 0%   (0/1)0%   (0/2)0%   (0/1)
setP4Synctime (String): void 0%   (0/1)0%   (0/3)0%   (0/1)
setTsmTestrun (String): void 0%   (0/1)0%   (0/3)0%   (0/1)
setWasSystemErrLogFile (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
setWasSystemOutLogFile (String): void 0%   (0/1)0%   (0/3)0%   (0/2)
writeFileBytes (File, byte []): void 0%   (0/1)0%   (0/35)0%   (0/10)

1/**
2 * Copyright 2007 ATG DUST Project
3 * 
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 
7 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
8 * 
9 * Unless required by applicable law or agreed to in writing, software 
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and limitations under the License.
13 */
14 
15package atg.junit.nucleus;
16 
17import java.io.BufferedReader;
18import java.io.ByteArrayOutputStream;
19import java.io.File;
20import java.io.FileOutputStream;
21import java.io.IOException;
22import java.io.InputStreamReader;
23import java.io.PrintStream;
24import java.lang.reflect.Method;
25import java.net.InetAddress;
26import java.net.MalformedURLException;
27import java.net.URL;
28import java.net.UnknownHostException;
29import java.util.Iterator;
30import java.util.LinkedList;
31import java.util.List;
32import java.util.Map;
33import java.util.Properties;
34import java.util.StringTokenizer;
35import java.util.jar.Manifest;
36 
37import javax.activation.DataHandler;
38import javax.activation.FileDataSource;
39import javax.mail.BodyPart;
40import javax.mail.Message;
41import javax.mail.Multipart;
42import javax.mail.internet.MimeBodyPart;
43import javax.mail.internet.MimeMultipart;
44 
45import org.apache.log4j.Logger;
46import org.w3c.dom.Node;
47 
48import atg.applauncher.AppLauncher;
49import atg.applauncher.AppModule;
50import atg.nucleus.DynamoEnv;
51import atg.nucleus.Nucleus;
52import atg.service.dynamo.LicenseImpl;
53import atg.service.email.ContentPart;
54import atg.service.email.EmailEvent;
55import atg.service.email.MimeMessageUtils;
56import atg.service.email.SMTPEmailSender;
57import atg.servlet.ServletUtil;
58 
59/**
60 * This class is used to hold useful utilty methods people may
61 * need when running tests.
62 */
63public class TestUtils
64  extends atg.nucleus.GenericService
65{
66  
67  private static Logger log = Logger.getLogger(TestUtils.class);
68  // names of app servers types that may be specified by the
69  // 'atg.dynamo.appserver' system property
70  // Dynamo currently does not distinguish between generic
71  // Tomcat and JBoss, everything is just referred to as 'tomcat' 
72  public static final String APP_SERVER_DAS = "das";
73  public static final String APP_SERVER_BEA = "weblogic";
74  public static final String APP_SERVER_IBM = "websphere";
75  public static final String APP_SERVER_TOMCAT = "tomcat";
76        
77  // names of various vendors that ATG works with
78  public static final String VENDOR_ATG = "ATG";
79  public static final String VENDOR_BEA = "BEA";
80  public static final String VENDOR_IBM = "IBM";
81  public static final String VENDOR_JBOSS = "JBOSS";
82        
83  // the variable that points to the installation directory for dynamo
84  private static final String ROOT_VAR = "atg.dynamo.root";
85  private static final String HOME_VAR = "atg.dynamo.home";
86  private static final String ATG_J2EESERVER_ROOT = "atg.j2eeserver.root";
87 
88  // these are used to lookup some system settings from the VM
89  private static final String JAVA_VAR = "java.vm.info";
90  private static final String JAVA_VERSION = "java.vm.version";
91  private static final String JAVA_BUILD_VERSION = "java.version";
92  private static final String COMPILER_VAR = "java.compiler";
93  private static final String OS_VAR = "os.name";
94  private static final String OS_VERSION_VAR = "os.version";
95 
96  // the system variable that returns the name of the app server being used
97  private static final String APP_SERVER = "atg.dynamo.appserver";
98    
99  // the Configuration component used by Dynamo
100  private static final String CONFIGURATION_COMPONENT = "/atg/dynamo/Configuration";
101 
102  // mailhost used to send email
103  private static final String MAILHOST = "mailsvr.atg.com";
104    
105  // value returned by several methods, as noted in javadoc, if a
106  // piece of information can not be definitively determined.  in
107  // particular, used when reporting about product build and version
108  // information
109  public static final String UNKNOWN_INFO = "unknown";
110    
111  /** property to track the DUST version being used.  utilized by
112   *  ATGXMLFileTestResultReported so we can tag XML result files for
113   *  compatibility validation when passed to the XML file logger  */
114  public static int DUST_VERSION = 1;
115 
116  /** specifies the DUST version being used.  utilized by
117   *  ATGXMLFileTestResultReporter so XML result files can be tagged
118   *  for compatibility validation when passed to the XML file
119   *  logger */
120  public void setDustVersion( int pVersion ) { DUST_VERSION = pVersion; }
121 
122  /** returns the DUST version being used.  utilized by
123   *  ATGXMLFileTestResultReporter so XML result files can be tagged
124   *  for compatibility validation when passed to the XML file
125   *  logger */
126  public int getDustVersion() { return DUST_VERSION; }
127            
128  /** property to track the DUST user.  utilized when results are
129   *  logged to the database to correlate the result with a user
130   *  account in the test management system. */
131  public static String DUST_USERNAME = System.getProperty( "user.name" );
132 
133  /** specifies the DUST user.  utilized when results are logged to
134   *  the database to correlate the result with a user account in the
135   *  test management system. */
136  public void setDustUsername( String pUsername ) { DUST_USERNAME = pUsername; }
137  /** returns the DUST user name.  utilized when results are logged to
138   *  the database to correlate the result with a user account in the
139   *  test management system. */
140  public String getDustUsername() { 
141    if ( DUST_USERNAME == null || DUST_USERNAME.trim().length() == 0 )
142      return System.getProperty( "user.name" );
143    else return DUST_USERNAME; 
144  }
145        
146  /** property to track which testrun a result is part of.  utilized
147   *  by TSM to correlate a specifid result with the testrun used to
148   *  install and configure the test Dynamo. */
149  public static String TSM_TESTRUN = null;
150 
151  /** Specifies the TSM testrun this result is part of.  utilized by
152   *  TSM to correlate a specifid result with the testrun used to
153   *  install and configure the test Dynamo. */        
154  public void setTsmTestrun( String pId ) { TSM_TESTRUN = pId; }
155 
156  /** Returns the TSM testrun this result is part of.  utilized by TSM
157   *  to correlate a specifid result with the testrun used to install
158   *  and configure the test Dynamo. */        
159  public String getTsmTestrun() { return TSM_TESTRUN; }
160                
161  /** property to track the p4 sync time for tests.  utilized by TSM
162   *  to inform end-users of time at which machine was last synced.
163   *  must be specified by test setup before test is run. */
164  public static String P4SYNCTIME = null;
165 
166  /** property to track the p4 sync time for tests.  utilized by TSM
167   *  to inform end-users of time at which machine was last synced.
168   *  must be specified by test setup before test is run. */
169  public void setP4Synctime( String pTime ) { P4SYNCTIME = pTime; }
170 
171  /** property to track the p4 sync time for tests.  utilized by TSM
172   *  to inform end-users of time at which machine was last synced.
173   *  must be specified by test setup before test is run. */
174  public String setP4Synctime() { return P4SYNCTIME; }
175 
176  /** Returns the directory in which Dynamo was installed.  If the
177   *  installation directory was not specified during the DUST
178   *  installation, returns null.  Should <b>only</b> be used by
179   *  System tests. */
180  public static File DYNAMO_INSTALL_DIR = null;
181 
182  /** Returns the directory in which Dynamo was installed.  If the
183   * installation directory can not be successfully determined returns
184   * null.
185   * <br><b>NOTE:</b> There is no reliable System property (or
186   * other inherent mechanism) to determine the Dynamo installation
187   * directory when running as BigEar, so this value is set during the
188   * DUST build process.  The SystemTests.base build step writes the
189   * file
190   * SystemTests/base/config/atg/junit/nucleus/TestUtils.properties
191   * with the proper value.  Consequently, this method should only be
192   * used by System tests, not Unit tests.
193   */
194  public File getDynamoInstallDir() { return DYNAMO_INSTALL_DIR; }
195 
196  /** Specifies the directory in which Dynamo was installed. */
197  public void setDynamoInstallDir( File pDir ) { DYNAMO_INSTALL_DIR = pDir; }
198        
199  /** Returns the root directory for this Dynamo.  If the root
200   * directory can not be successfully located returns null.  Operates
201   * according to this logic:
202   * <ul>
203   *   <li>If "home" Dynamo module can be found, return parent directory
204   *       containing that module.  (This should resolve when running 'BigEar')
205   *   <li>Otherwise, return value of System property 'atg.dynamo.root'.
206   *       (this could still be null)
207   * </ul>
208   */
209  public static File getDynamoRootDir() {
210    File root = null;
211    try { root = getDynamoHomeDir().getParentFile(); }
212    catch (Throwable t) {}
213    if ( root == null ) {
214      try { root = new File( System.getProperty( ROOT_VAR ) ); }
215      catch (Throwable t) {}
216    }
217    return root;
218  }
219        
220  /** Returns Dynamo's "home" module installation directory.  If the
221   *  directory can not be successfully located returns null.
222   *  <br>Logic works like this:
223   *  <ul>
224   *    <li>If "home" Dynamo module can be found, return directory representing
225   *        that module.  This should resolve when running 'BigEar' and may
226   *        point to a subdirectory of the application server's directory used
227   *        to deploy ear files.  On DAS it should resolve to
228   *        <DYNAMO_INSTALL_DIR>/home.
229   *    <li>Otherwise, return value of System property 'atg.dynamo.home'.
230   *        (this could be null)
231   *  </ul>
232   */
233  public static File getDynamoHomeDir() {
234    File root = null;
235    try { root = getModuleResourceFile("home",".").getCanonicalFile(); }
236    catch (Throwable t) {}
237    if ( root == null ) {
238      try { root = new File( System.getProperty( HOME_VAR ) ); }
239      catch (Throwable t) {}
240    }
241 
242    return root;
243  }
244 
245  /** returns the root install directory for the ATG J2EE Server, or null if
246   *  the ATG J2EE Server is not installed. */
247  public static File getAtgJ2eeServerInstallDir() {
248    try { return new File(System.getProperty( ATG_J2EESERVER_ROOT )); }
249    catch (Throwable t) { return null; }
250  }
251 
252 
253  /** Returns the product name of the app server being used. For ATG
254   *  we currently assume it's called 'ATGDAS' if it's a separate
255   *  product, since there is no definitive way to figure out the
256   *  product name from MANIFEST files. For all other app servers it
257   *  returns the value of getAppServerType().
258   */
259  public static String getAppServerProductName() {
260    if ( getAppServerType().equals( APP_SERVER_DAS ) ) return getAtgJ2eeServerProductName();
261    else return getAppServerType();
262  }
263        
264  /** Returns the name of the ATG J2EE Server product this is installed, or
265   *  null if a separate ATG J2EE Server build is not installed. */
266  public static String getAtgJ2eeServerProductName() {
267    // TODO: Bug 78552 was opened to add a MANIFEST entry containing
268    // the product name so we don't have to hard code this to
269    // 'ATGDAS'.
270    if ( getAtgJ2eeServerInstallDir() != null ) return "ATGDAS";
271    else return null;
272  }        
273        
274  /** Returns the version number of the app server being used.  For
275   *  DAS this version comes from the J2EEServer MANIFEST file, or is
276   *  UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
277   *  case if a person is using devtools to build their product. For
278   *  3PAS the version number is extracted from their configuration
279   *  file (typically some well known XML file).
280   */
281  public static String getAppServerVersion() {
282    String apptype = getAppServerType();
283    if ( apptype.equals( APP_SERVER_DAS ) ) {
284      return getAtgVersion( getAtgJ2eeServerModule() );
285    } else if ( apptype.equals( APP_SERVER_BEA ) ) {
286      return getBeaVersion();
287    } else if ( apptype.equals( APP_SERVER_IBM ) ) {
288      return getWasVersion();
289    } else if ( apptype.equals( APP_SERVER_TOMCAT ) ) {
290      return getJBossVersion();
291    } else {
292      return UNKNOWN_INFO;
293    }
294  }
295         
296  /** Returns the build number of the app server being used.  For DAS
297   *  this version comes from the J2EEServer MANIFEST file, or is
298   *  UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
299   *  case if a person is using devtools to build their product. For
300   *  3PAS the build number is always UNKNOWN_INFO.
301   */
302  public static String getAppServerBuildNumber() {
303    String apptype = getAppServerType();
304    if ( apptype.equals( APP_SERVER_DAS ) ) {
305      return getAtgBuildNumber( getAtgJ2eeServerModule() );
306    } else {
307      return UNKNOWN_INFO;
308    }
309  }         
310 
311  /** Returns the patch version of the app server being used.  For DAS
312   *  this version comes from the J2EEServer MANIFEST file, or is
313   *  UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
314   *  case if a person is using devtools to build their product. For
315   *  3PAS the patch version is always UNKNOWN_INFO.
316   */
317  public static String getAppServerPatchVersion() {
318    String apptype = getAppServerType();
319    if ( apptype.equals( APP_SERVER_DAS ) ) {
320      return getAtgPatchVersion( getAtgJ2eeServerModule() );
321    } else {
322      return UNKNOWN_INFO;
323    }
324  }        
325 
326  /** Returns the patch build number of the app server being used.
327   *  For DAS this version comes from the J2EEServer MANIFEST file, or
328   *  is UNKNOWN_INFO if the MANIFEST can't be found. Such may be the
329   *  case if a person is using devtools to build their product. For
330   *  3PAS the patch build number is always UNKNOWN_INFO.
331   */
332  public static String getAppServerPatchBuildNumber() {
333    String apptype = getAppServerType();
334    if ( apptype.equals( APP_SERVER_DAS ) ) {
335      return getAtgPatchBuildNumber( getAtgJ2eeServerModule() );
336    } else {
337      return UNKNOWN_INFO;
338    }
339  }        
340         
341  /** Returns the vendor name of the App server manufacturer.  if a
342   *  vendor can not be determined it returns UNKNOWN_INFO.
343   */
344  public static String getAppServerVendor() {
345    String apptype = getAppServerType();
346    if ( apptype.equals( APP_SERVER_DAS ) ) {
347      return VENDOR_ATG;
348    } else if ( apptype.equals( APP_SERVER_BEA ) ) {
349      return VENDOR_BEA;
350    } else if ( apptype.equals( APP_SERVER_IBM ) ) {
351      return VENDOR_IBM;
352    } else if ( apptype.equals( APP_SERVER_TOMCAT ) ) {
353      return VENDOR_JBOSS;
354    } else {
355      return UNKNOWN_INFO;
356    }
357  }
358 
359  /** Returns true if the Dynamo product is being used; false if only the ATG
360   *  J2EE Server product is running. 
361   **/
362  public static boolean isDynamoInstalled() 
363  {
364    try {
365      // if j2ee server is not installed then Dynamo must be...
366      if ( getAtgJ2eeServerInstallDir() == null ) return true;
367      // if the j2ee server root is the same as the dynamo root then
368      // we're running only the j2ee server
369      else return ( ! getAtgJ2eeServerInstallDir().getCanonicalFile().equals(getDynamoRootDir().getCanonicalFile() ) );
370    } catch ( IOException ioe ) {
371      // this should never happen, but if it does return false...
372      return false;
373    }
374  }
375 
376  /** This method returns the name of the Dynamo product that is
377   *  installed.  Because there is no guaranteed way to determine the
378   *  installed product this method makes a best-guess.  If the
379   *  version is less than 5.5 then the method skips down from DCS, to
380   *  DPS, etc. until it finds a product that exists. If the version
381   *  5.5, 5.6, or 5.6.1 then this method just returns 'AppDAP' since
382   *  that is the only Dynamo product we have for those versions.
383   *  Likewise, if the version is NOT anything between 4 and 5.6, then
384   *  we return 'ATG' since that is the only version we have for
385   *  copper, etc.  If the method can't determine a version it returns
386   *  UNKNOWN_INFO
387   */
388  public static String getDynamoProductName() 
389  {
390    AppModule module = getAtgDynamoModule(); 
391    if ( module == null ) return UNKNOWN_INFO;       
392    String version = getAtgVersion(module); 
393            
394    if ( version == null ) {
395      return UNKNOWN_INFO;
396    } else if ( version.startsWith("5.5") || version.startsWith("5.6") ) {
397      // this is an AppDAP build of 5.5, 5.6, or 5.6.1
398      return "AppDAP";
399    } else if ( ! version.startsWith("4") && ! version.startsWith("5.0") && ! version.startsWith("5.1") ) {
400      // assume this is an ATG build from version 6.x
401      // TODO: Bug 78552 was opened to add a MANIFEST entry containing
402      // the product name so we don't have to guess at it.
403      return "ATG";
404    } else {
405      return UNKNOWN_INFO;
406    }
407  }
408 
409  /** Returns information about the ATG Dynamo product being used.
410   * does not include information about the app server that may be in
411   * use.  returns null if Dynamo is not running.
412   **/
413  public static String getDynamoProductInfo() 
414  {
415    StringBuffer sb = new StringBuffer();
416    AppModule dynamo = getAtgDynamoModule();
417                
418    if ( dynamo == null ) return null;
419                
420    sb.append( getDynamoProductName() + " version " + getAtgVersion(dynamo) );
421    String build = getAtgBuildNumber(dynamo);
422    if ( ! build.equals(UNKNOWN_INFO) ) sb.append( " build " + build);
423    String patch_version = getAtgPatchVersion(dynamo);
424    String patch_build   = getAtgPatchBuildNumber(dynamo);
425    if ( ! (patch_version == null) && ! patch_version.equals(UNKNOWN_INFO) )
426      sb.append( " with patch " + patch_version + " build " + patch_build );
427                   
428    return sb.toString();                
429  }
430 
431  /** Returns a summary of information about the App Server product
432   * being used.
433   */
434  public static String getAppServerProductInfo() {
435    StringBuffer sb = new StringBuffer();
436                
437    sb.append(getAppServerProductName() + " version " + getAppServerVersion());
438    String build = getAppServerBuildNumber();
439    if ( ! build.equals(UNKNOWN_INFO) ) sb.append( " build " + build);
440    String patch_version = getAppServerPatchVersion();
441    String patch_build   = getAppServerPatchBuildNumber();
442    if ( ! (patch_version == null) && ! patch_version.equals(UNKNOWN_INFO) )
443      sb.append( " with patch " + patch_version + " build " + patch_build );
444                   
445    return sb.toString();
446  }
447 
448  /** returns the java version that Dynamo is using
449   *
450   * @return String version of java Dynamo is using
451   */
452  public static String getJavaVersion() {
453    return System.getProperty( JAVA_VERSION );
454  }
455 
456  /** returns the java build version (java.version) that Dynamo is using
457   *
458   *  @return String build version of java Dynamo is using
459   */
460  public static String getJavaBuildVersion() {
461    return System.getProperty( JAVA_BUILD_VERSION );
462  }
463 
464  /** returns detailed version information about the jdk being used */
465  public static String getJavaVersionDetails() {
466    return TestUtils.getJavaInfo() + " - " + TestUtils.getJavaVersion();
467  }
468        
469  /** returns info about the java build that Dynamo is using
470   *
471   * @return String info about java build Dynamo is using
472   */
473  public static String getJavaInfo() {
474    return System.getProperty( JAVA_VAR );
475  }
476 
477  /** returns the type of compiler that Dynamo is using
478   *
479   * @return String compiler Dynamo is using
480   */
481  public static String getCompilerType() {
482    return System.getProperty( COMPILER_VAR );
483  }
484 
485  /** returns the type of Operating System that Dynamo is running on
486   */
487  public static String getOperatingSystemType() {
488    return System.getProperty( OS_VAR )
489      + " version " + System.getProperty( OS_VERSION_VAR );
490  }
491 
492  /** returns the hostname of the machine that Dynamo is running on
493   */
494  public static String getHostname() {
495    try {
496      InetAddress address = InetAddress.getLocalHost();
497      return address.getHostName();
498    } catch (UnknownHostException uhe) {}
499 
500    return "unknown";
501  }
502 
503  /** returns the name of the app server that dynamo is using */
504  public static String getAppServerType() {
505    if ( ServletUtil.isWebLogic() ) return APP_SERVER_BEA;
506    else if ( ServletUtil.isWebSphere() ) return APP_SERVER_IBM;
507    else if ( ServletUtil.isDynamoJ2EEServer() ) return APP_SERVER_DAS;
508    else if ( isGenericAppServer() ) return APP_SERVER_TOMCAT;
509    else return System.getProperty( APP_SERVER );
510  }
511        
512  /** Returns true if Dynamo is running on a 'generic' (aka Tomcat)
513   *  j2ee appserver; false otherwise.
514   *  ServletUtil.isGenericJ2EEServer() method call does not exist in
515   *  early Dynamo versions, so use reflection to invoke it.  As of
516   *  ATG 7x, isGenericJ2EEServer() really means "are we running on
517   *  JBOSS" - I'm not sure whether we intend to differentiate between
518   *  JBOSS and other 'generic' Tomcat app servers.
519   */
520  public static boolean isGenericAppServer() {
521    try {
522      ServletUtil.class.newInstance();
523      return ((Boolean) invokeMethod(dynamoEnv(), "isGenericJ2EEServer", null, null, null)).booleanValue();
524    } catch (Throwable t) {}
525    return false;
526  }
527 
528  /** returns the WAS home directory if running on WAS.  otherwise,
529   * returns null */
530  public static String getWasHomeDir() {
531    return System.getProperty( "was.install.root" );
532  }
533        
534  /** returns the WAS version number.  if not running against WAS, or
535   *  if the {WAS.install.root}/properties/version/BASE.product file
536   *  can not be found, or if an error occurs parsing the file then
537   *  returns UNKNOWN_INFO.
538   */            
539  public static String getWasVersion() {
540    String version = null;                                
541    try {
542      // WAS 5
543      File f = new File( getWasHomeDir(), "properties/version/BASE.product" );
544      // WAS 6
545      if (!f.exists())
546        f = new File( getWasHomeDir(),"properties/version/WAS.product" );
547 
548      String[] children1 = { "version" };
549      List<Node> nodes1 = XmlUtils.getNodes(f, false, children1);
550      if (nodes1 != null ) {
551        Iterator<Node> iter1 = nodes1.iterator();
552        while (iter1.hasNext()) {
553          Node n1 = iter1.next();
554          version = XmlUtils.getNodeTextValue(n1);
555        }
556      }
557    } catch (Throwable e) {}
558                        
559    if ( version != null ) return version;
560    else return UNKNOWN_INFO;
561  }
562 
563        
564  /** returns the full file path of specified was log if
565   * getWasHomeDir() is not null.  otherwise returns null. */
566  private static File getWasLogFile( String pServerName, String pLogName )
567  {
568    if ( getWasHomeDir() == null ) return null;
569    else return new File( getWasHomeDir(), "logs" + File.separator + pServerName + File.separator + pLogName );
570  }
571        
572  private static String mWasSystemOutLogFile = null;
573 
574  /** Specifies the log file to return when asked for the WAS
575   *  'SystemOut.log' file.  if this value is null we attempt to
576   *  calculate a default location */
577  public void setWasSystemOutLogFile( String pFile ) {
578    mWasSystemOutLogFile = pFile;
579  }
580 
581  /** returns the expected location of the WAS 'SystemOut.log' file if
582   * running on WAS.  otherwise returns null.*/
583  public static String getWasSystemOutLogFile() {
584    if ( getWasHomeDir() == null ) return null;
585    else if (mWasSystemOutLogFile != null
586             && mWasSystemOutLogFile.trim().length() > 0)
587      return mWasSystemOutLogFile.trim();
588    else {
589      File f = getWasLogFile(ServletUtil.getWebsphereServerName(),"SystemOut.log");
590      if (f == null || ! f.exists())
591        f = getWasLogFile( "server1", "SystemOut.log" );
592               
593      if ( f != null ) return f.getAbsolutePath();
594    }
595    return null;
596  }
597 
598  private static String mWasSystemErrLogFile = null;
599 
600  /** Specifies the log file to return when asked for the WAS
601   *  'SystemErr.log' file.  if this value is null we attempt to
602   *  calculate a default location */
603  public void setWasSystemErrLogFile( String pFile ) {
604    mWasSystemErrLogFile = pFile;
605  }
606 
607  /** returns the expected location of the WAS 'SystemErr.log' file if
608   * running on WAS.  otherwise returns null.*/
609  public static String getWasSystemErrLogFile() {
610    if ( getWasHomeDir() == null ) return null;
611    else if (mWasSystemErrLogFile != null
612             && mWasSystemErrLogFile.trim().length() > 0)
613      return mWasSystemErrLogFile.trim();
614    else {
615      File f = getWasLogFile(ServletUtil.getWebsphereServerName(),"SystemErr.log");
616      if ( f == null || ! f.exists() )
617        f = getWasLogFile( "server1", "SystemErr.log" );
618               
619      if ( f != null ) return f.getAbsolutePath();
620    }
621    return null;
622  }
623 
624  /** returns the BEA home directory if running on BEA.  otherwise,
625   * returns null */
626  public static String getBeaHomeDir() { 
627    String homedir = System.getProperty( "bea.home" );
628    if ( homedir != null ) return homedir;
629                
630    // sometimes (like on bea 8) 'bea.home' is not specified, so try
631    // to determine bea.home base on another property...
632    String startfile = System.getProperty( "java.security.policy" );
633    if ( startfile != null ) {
634      // the policy file is (hopefully) always located at a location like:
635      // /root/to/bea/<weblogic>/server/lib/weblogic.policy
636      // so we basically want to go up four levels from there...
637      homedir = atg.core.io.FileUtils.getParent( startfile );
638      // should now be in /root/to/bea/<weblogic>/server/lib
639      homedir = atg.core.io.FileUtils.getParent( homedir );
640      // should now be in /root/to/bea/<weblogic>/server
641      homedir = atg.core.io.FileUtils.getParent( homedir );
642      // should now be in /root/to/bea/<weblogic>
643      homedir = atg.core.io.FileUtils.getParent( homedir );
644      // should now be in /root/to/bea
645    }
646                
647    return homedir;
648  }
649 
650  private static String mBeaMyServerLogFile = null;
651 
652  /** Specifies the log file to return when asked for the BEA
653   *  'myserver.log' file.  if this value is null then a default value
654   *  will be calculated. */
655  public static void setBeaMyServerLogFile( String pFile ) {
656    mBeaMyServerLogFile = pFile;
657  }
658 
659  /** returns the expected location of the BEA 'myserver.log' file if
660   * running on BEA.  otherwise returns null.*/
661  public static String getBeaMyServerLogFile() {
662    if ( getBeaHomeDir() == null ) return null;
663    else if (mBeaMyServerLogFile != null
664             && mBeaMyServerLogFile.trim().length() > 0 )
665      return mBeaMyServerLogFile.trim();
666    else {
667      // try this default location....
668      String name = "user_projects" + File.separator +
669        "mydomain" + File.separator +
670        "myserver" + File.separator +
671        "myserver.log";
672      File log = new File( getBeaHomeDir(), name );
673               
674      if ( log.exists() ) {
675        return log.getAbsolutePath();
676      } else {
677        // the default didn't work (as we shouldn't always expect it
678        // to) so try this location...  'user.dir' typically points to
679        // the domain dir: /path/to/bea/user_projects/mydomain
680        // 'weblogic.Name' should be like : myserver
681        name = System.getProperty( "user.dir" ) + File.separator + 
682          System.getProperty( "weblogic.Name" ) + File.separator +
683          System.getProperty( "weblogic.Name" ) + ".log";
684        log = new File( name );
685        if ( log.exists() ) return log.getAbsolutePath();
686      }
687    }
688    return null;
689  }
690 
691  /** returns the BEA version number.  if not running against BEA, or if
692   *  the {BEA_HOME}/registry.xml file can not be found, or if an error occurs
693   *  parsing the file then returns UNKNOWN_INFO.
694   */
695  public static String getBeaVersion() 
696  {
697    String version = null;
698    try {
699      File f = new File( new File( getBeaHomeDir() ), "registry.xml" );
700      String[] children = { "host", "product", "release" };
701      List<Node> nodes = XmlUtils.getNodes(f, false, children);
702      if ( nodes != null ) {
703        Iterator<Node> iter = nodes.iterator();
704        // I expect there to only be one <host><product><release> node
705        // so this iteration should really just loop over one node.
706        while ( iter.hasNext() ) {
707          Node n =  iter.next();
708          version = XmlUtils.getAttribute(n,"level","0") + "." +
709            XmlUtils.getAttribute(n,"ServicePackLevel","0") + "." +
710            XmlUtils.getAttribute(n,"PatchLevel","0");
711        }
712      }
713    } catch (Throwable e) {
714    }
715            
716    if ( version != null ) return version;
717    else return UNKNOWN_INFO;
718  }
719        
720  // ---------------- JBOSS Utility Methods --------------------------
721  // NOTE: Available JBoss System property names can be found in class
722  // org.jboss.system.server.ServerConfig
723        
724  /** Returns the JBOSS installation home directory, if Dynamo is
725   * running on JBOSS.  Otherwise returns null. */
726  public static File getJBossHomeDir() {
727    String dir = System.getProperty("jboss.home.dir");
728    if ( dir == null ) return null;
729    else return new File(dir);
730  }
731        
732  /** Returns the JBOSS server home directory, if Dynamo is running on
733   * JBOSS.  Otherwise returns null. */
734  public static File getJBossServerHomeDir() {
735    String dir = System.getProperty("jboss.server.home.dir");
736    if ( dir == null ) return null;
737    else return new File(dir);
738  }
739        
740  /** Returns the JBOSS server name, if Dynamo is running on JBOSS.
741   * Otherwise returns null. */
742  public static String getJBossServerName() {
743    return System.getProperty("jboss.server.name");
744  }
745        
746  /** Returns the path to the JBOSS server log file, if it can be
747   * found.  Otherwise returns null */
748  public static String getJBossServerLog() {
749    try {
750      File log = new File( getJBossServerHomeDir(), "log/server.log" );
751      if ( log.exists() ) return log.getAbsolutePath();
752    } catch ( Throwable t ) {}
753    return null;
754  }
755        
756  /** Returns the version of JBOSS being used, if it can be
757   *  determined.  Otherwise returns UNKNOWN_INFO.  This method
758   *  expects to find a 'jar-versions.xml' file in the JBoss home
759   *  directory. It searches for the &lt;jar&gt; element whose 'name'
760   *  attribute is "jboss.jar", and determines the version based on
761   *  the value of the 'implVersion' attribute.
762   **/
763  public static String getJBossVersion() {
764    try {
765      File versionFile = new File( getJBossHomeDir(), "jar-versions.xml");
766      if (!versionFile.exists()) {
767        log("jar-versions.xml file does not exist; "
768            + "unable to determine version info");
769        return UNKNOWN_INFO;
770      }
771      String[] children = { "jar" };
772      Iterator<Node> nodes = XmlUtils.getNodes(versionFile,false,children).iterator();
773      while ( nodes.hasNext() ) {
774        try {
775          Node node =  nodes.next();
776          String name = node.getAttributes().getNamedItem("name").getNodeValue();
777          log("Checking node: " + name);
778          if ( name.equals("jboss.jar") ) {
779            String ver = node.getAttributes().getNamedItem("implVersion").getNodeValue().trim();
780            log("JBOSS version string: " + ver);
781            // implVersion is typically something like 
782            // "4.0.1sp1 (build: CVSTag=JBoss_4_0_1_SP1 date=200502160314)"
783            // so, strip off the build information since we don't care about it
784            int idx = ver.indexOf(" (build:");
785            if ( idx != -1 ) ver = ver.substring(0,idx).trim();
786            return ver;
787          }
788        } catch (Throwable ti) {}
789      }
790    } catch (Throwable t) {}
791    return UNKNOWN_INFO;
792  }
793 
794  private static atg.service.dynamo.Configuration DYN_CONFIG = null;
795 
796  /** returns the Configuration component being used by Dynamo */
797  public static atg.service.dynamo.Configuration getDynamoConfiguration() {
798    if ( DYN_CONFIG == null ) {
799      try {
800        DYN_CONFIG = (atg.service.dynamo.Configuration) Nucleus.getGlobalNucleus().resolveName( CONFIGURATION_COMPONENT );
801      } catch (Throwable t) {}
802    }
803    return DYN_CONFIG;
804  }
805 
806  /** returns the session limit of the specified license component
807   *  @param String the component name of the license in question
808   *  @param boolean true if Nucleus should attempt to create the license
809   *  component if it does not exist
810   *  @return int the session limit for the license.  0 if the license does not
811   *  resolve.
812   **/
813  public static int getSessionLimit( String pLicense, boolean pResolve )
814  {
815    if ( pLicense == null ) return 0;
816    LicenseImpl license = (LicenseImpl) Nucleus.getGlobalNucleus().resolveName( pLicense, pResolve );
817    if ( license == null ) return 0;
818    return license.getMaxSessions();
819  }
820 
821  // ==================== EMAIL ======================
822 
823  /** This method is used to send an email message and allows the user
824   *  to specify the return address.
825   *  @return boolean true if the mail was sent successfully; otherwise false.
826   */
827  public static boolean sendEmailWithReturn(String pAddress, String pMsg,
828                                            String pSubject,
829                                            String pBodyEncoding,
830                                            String pReturnAddress )
831  {
832    try {
833      // create a Message with the given From and Subject
834      Message msg = MimeMessageUtils.createMessage( pReturnAddress, pSubject);
835      // set the To recipient
836      MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
837 
838      // set the message content: multipart message + attachment
839      if ( pBodyEncoding == null || pBodyEncoding.trim().length() == 0 )
840        pBodyEncoding = "text/plain";
841      ContentPart[] content =
842        { new ContentPart( pMsg, pBodyEncoding) };
843      MimeMessageUtils.setContent(msg, content);
844 
845      // create the email event
846      EmailEvent em = new EmailEvent(msg);
847 
848      // now send the event
849      SMTPEmailSender sender = new SMTPEmailSender();
850      sender.setEmailHandlerHostName( MAILHOST );
851      sender.sendEmailEvent( em );
852    } catch (Exception e) {
853      log.info("Caught exception sending email: " + e.toString() );
854      return false;
855    }
856    return true;
857  }
858 
859  /** This method is used to send an email message; returns true if
860   * everything went ok; otherwise, returns false
861   */
862  public static boolean sendEmail(String pAddress, String pMsg,
863                                  String pSubject, String pBodyEncoding)
864  {
865    return sendEmailWithReturn(pAddress,pMsg,pSubject,pBodyEncoding,pAddress);
866  }
867 
868  /** This method is used to send an email message; returns true if
869   * everything went ok; otherwise, returns false
870   */
871  public static boolean sendEmail(String pAddress, String pMsg,
872                                  String pSubject)
873  {
874    return sendEmail( pAddress, pMsg, pSubject, "text/plain" );
875  }
876 
877  /** This method is used to send the same email message to a vector
878   * of recipients
879   */
880  public static void sendEmails(List<String> pAddresses, String pMsg,
881                                String pSubject, String pBodyEncoding )
882  {
883    // make sure addresses are valid
884    if ( pAddresses == null ||
885         pAddresses.size() <= 0 )
886      return;
887 
888    // send emails
889    Iterator<String> addresses = pAddresses.iterator();
890    String address = null;
891    while ( addresses.hasNext() ) {
892      try {
893        address =  addresses.next();
894        if ( address != null && address.trim().length() > 0 )
895          sendEmail(address.trim(),pMsg,pSubject,null,null,null,pBodyEncoding);
896      } catch (Exception e) {}
897    }
898  }
899 
900  /** This method is used to send the same email message to a vector
901   *  of recipients.  It encodes the message body as "text/plain".
902   */
903  public static void sendEmails(List<String> pAddresses, String pMsg,
904                                String pSubject )
905  {
906    sendEmails( pAddresses, pMsg, pSubject, "text/plain" );
907  }
908 
909  /** This method is used to send an email message that contains
910   *  several attachments.  This method is specifically designed to
911   *  accept a map of java.lang.Strings as content parts instead of
912   *  java.io.Files.  The key in the Map should be a String
913   *  representing the name that you would like to show for the
914   *  attached file.  The value in the Map should be a String
915   *  representing the contents of the attachment.
916   */
917  public static void sendEmail(String pAddress, String pMsg, String pSubject,
918                               Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments,
919                               File[] pFiles, String pBodyEncoding )
920  {
921    try {
922      // make sure addresses are valid
923      if ( pAddress == null ||
924           pAddress.trim().length() == 0 )
925        return;
926 
927      // create a Message with the given From and Subject
928      Message msg = MimeMessageUtils.createMessage( pAddress, pSubject);
929 
930      // set the To recipient
931      MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
932 
933      // create the MultiPart used to hold everything
934      Multipart mp = new MimeMultipart();
935 
936      // set the message content: multipart message + attachment
937      BodyPart guts = new MimeBodyPart();
938      if ( pBodyEncoding == null || pBodyEncoding.trim().length() == 0 )
939        pBodyEncoding = "text/plain";
940      guts.setContent( pMsg, pBodyEncoding );
941      mp.addBodyPart( guts );
942 
943      // add the text attachments
944      if ( pTextAttachments != null ) {
945        Iterator<String> textkeys = pTextAttachments.keySet().iterator();
946        while ( textkeys.hasNext() ) {
947          String key = textkeys.next();
948          Object val = pTextAttachments.get( key );
949          if ( val != null ) {
950            MimeBodyPart part = new MimeBodyPart();
951            part.setContent( val.toString(), "text/plain" );
952            part.setDisposition( MimeBodyPart.ATTACHMENT );
953            part.setDescription( key );
954            part.setFileName( key );
955            mp.addBodyPart( part );
956          }
957        }
958      }
959 
960      // add the html attachments
961      if ( pHTMLAttachments != null ) {
962        Iterator<String> htmlkeys = pHTMLAttachments.keySet().iterator();
963        while ( htmlkeys.hasNext() ) {
964          String key =  htmlkeys.next();
965          Object val = pHTMLAttachments.get( key );
966          if ( val != null ) {
967            MimeBodyPart part = new MimeBodyPart();
968            part.setContent( val.toString(), "text/html" );
969            part.setDisposition( MimeBodyPart.ATTACHMENT );
970            part.setDescription( key );
971            part.setFileName( key );
972            mp.addBodyPart( part );
973          }
974        }
975      }
976 
977      // add the File attachments
978      if ( pFiles != null ) {
979        for ( int i=0; i<pFiles.length; i++ ) {
980          MimeBodyPart part = new MimeBodyPart();
981          part.setDataHandler(new DataHandler(new FileDataSource(pFiles[i])));
982          part.setFileName( pFiles[i].getName() );
983          mp.addBodyPart( part );
984        }
985      }
986 
987      msg.setContent( mp );
988 
989      // create the email event
990      EmailEvent em = new EmailEvent(msg);
991 
992      // now send the event
993      SMTPEmailSender sender = new SMTPEmailSender();
994      sender.setEmailHandlerHostName( MAILHOST );
995      sender.sendEmailEvent( em );
996    } catch (Exception e) {
997      log.info("Caught exception sending email: " + e.toString() );
998      e.printStackTrace();
999    }
1000  }
1001 
1002  /** This method is used to send an email message that contains
1003   *  several attachments.  This method is specifically designed to
1004   *  accept a map of java.lang.Strings as content parts instead of
1005   *  java.io.Files.  The key in the Map should be a String
1006   *  representing the name that you would like to show for the
1007   *  attached file.  The value in the Map should be a String
1008   *  representing the contents of the attachment.  If you wish to
1009   *  attach java.io.Files, use the static methods found in
1010   *  atg.service.email.MimeMessageUtils.
1011   */
1012  public static void sendEmail(String pAddress, String pMsg, String pSubject,
1013                               Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments,
1014                               String pBodyEncoding )
1015  {
1016    sendEmail( pAddress, pMsg, pSubject, pTextAttachments, pHTMLAttachments, null, pBodyEncoding );
1017  }
1018 
1019  /** This method is used to send an email message that contains
1020   *  several attachments.  This method is specifically designed to
1021   *  accept a map of java.lang.Strings as content parts instead of
1022   *  java.io.Files.  The key in the Map should be a String
1023   *  representing the name that you would like to show for the
1024   *  attached file.  The value in the Map should be a String
1025   *  representing the contents of the attachment.  If you wish to
1026   *  attach java.io.Files, use the static methods found in
1027   *  atg.service.email.MimeMessageUtils.
1028   */
1029  public static void sendEmail( String pAddress, String pMsg, String pSubject,
1030                                Map<String, Object> pTextAttachments, Map<String, Object> pHTMLAttachments )
1031  {
1032    sendEmail( pAddress,pMsg,pSubject,pTextAttachments,pHTMLAttachments,"text/plain");
1033  }
1034 
1035 
1036  /** This method is used to send an email message that contains
1037   *  several attachments.  This method is specifically designed to
1038   *  accept a map of java.lang.Strings as content parts instead of
1039   *  java.io.Files.  The key in the Map should be a String
1040   *  representing the name that you would like to show for the
1041   *  attached file.  The value in the Map should be a String
1042   *  representing the contents of the attachment.
1043   */
1044  public static void sendEmails(List<String> pAddresses, String pMsg,
1045                                String pSubject, Map<String, Object> pTextAttachments,
1046                                Map<String, Object> pHTMLAttachments, File[] pFiles,
1047                                String pBodyEncoding )
1048  {
1049    // make sure addresses are valid
1050    if ( pAddresses == null ||
1051         pAddresses.size() <= 0 )
1052      return;
1053 
1054    // send emails
1055    Iterator<String> addresses = pAddresses.iterator();
1056    String address = null;
1057    while ( addresses.hasNext() ) {
1058      try {
1059        address =  addresses.next();
1060        if ( address != null && address.trim().length() > 0 )
1061          sendEmail(address.trim(), pMsg, pSubject, pTextAttachments,
1062                    pHTMLAttachments, pFiles, pBodyEncoding );
1063      } catch (Exception e) {}
1064    }
1065  }
1066 
1067  /** This method is used to send an email message that contains
1068   *  several attachments to multiple recipients.  This method is
1069   *  specifically designed to accept a map of java.lang.Strings as
1070   *  content parts instead of java.io.Files.  The key in the Map
1071   *  should be a String representing the name that you would like to
1072   *  show for the attached file.  The value in the Map should be a
1073   *  String representing the contents of the attachment.
1074   */
1075  public static void sendEmails(List<String> pAddresses, String pMsg,
1076                                String pSubject, Map<String, Object> pTextAttachments,
1077                                Map<String, Object> pHTMLAttachments, String pBodyEncoding )
1078  {
1079    sendEmails( pAddresses, pMsg, pSubject, pTextAttachments, pHTMLAttachments, null, pBodyEncoding );
1080  }
1081 
1082  /** This method is used to send an email message that contains
1083   *  several attachments to multiple recipients.  The message will
1084   *  have it's main body part encoded as "text/plain".  <br>This
1085   *  method is specifically designed to accept a map of
1086   *  java.lang.Strings as content parts instead of java.io.Files.
1087   *  The key in the Map should be a String representing the name that
1088   *  you would like to show for the attached file.  The value in the
1089   *  Map should be a String representing the contents of the
1090   *  attachment.  If you wish to attach java.io.Files, use the static
1091   *  methods found in atg.service.email.MimeMessageUtils.
1092   */
1093  public static void sendEmails(List<String> pAddresses, String pMsg,
1094                                String pSubject, Map<String, Object> pTextAttachments,
1095                                Map<String, Object> pHTMLAttachments )
1096  {
1097    sendEmails(pAddresses,pMsg,pSubject,pTextAttachments,pHTMLAttachments,"text/plain");
1098  }
1099 
1100  // ======================== EXCEPTIONS =====================
1101 
1102  /** this method returns a String representation of an Exception's stacktrace
1103   */
1104  public static String getStackTrace( Throwable pException ) {
1105    ByteArrayOutputStream bos = new ByteArrayOutputStream();
1106    PrintStream ps = new PrintStream( bos );
1107    pException.printStackTrace( ps );
1108    ps.flush();
1109    return bos.toString();
1110  }
1111 
1112  // ===================== URL ACCESS ========================
1113 
1114  /** this method returns the contents of the page specified as the
1115   *  URL.  the URL should be a fully qualified request string.  for
1116   *  example, http://rygar.atg.com:8880/some/directory/page.jhtml
1117   *
1118   *  If the boolean parameter is set to true then this method will
1119   *  throw an Exception if an error occurs; otherwise it will simply
1120   *  return the contents of the exception.
1121   *
1122   * @exception MalformedURLException if URL is malformed & pThrow is true
1123   * @exception IOException if error happens while reading and pThrow is true
1124   */
1125  public static String accessURL( String pUrl, boolean pThrow )
1126    throws MalformedURLException, IOException
1127  {
1128    URL url = null;
1129    StringBuffer results = new StringBuffer();
1130    BufferedReader in = null;
1131    InputStreamReader isr = null;
1132    try {
1133      url = new URL( pUrl );
1134 
1135      isr = new InputStreamReader( url.openStream() );
1136      in = new BufferedReader( isr );
1137      String line = null;
1138      while ( ( line = in.readLine() ) != null ) {
1139        results.append( line + "\n" );
1140      }
1141      return results.toString();
1142    } catch ( MalformedURLException e ) {
1143      if ( pThrow )
1144        throw e;
1145      else
1146        results.append( "\nEncountered an unexpected error while trying to retrieve the configuration info." +
1147                        "\nWhen the url " + url + " was requested, this error was received: \n" + getStackTrace( e ) + "\n" );
1148    } catch ( IOException ioe ) {
1149      if ( pThrow )
1150        throw ioe;
1151      else
1152        results.append( "\nEncountered an unexpected error while trying to retrieve the configuration info." +
1153                        "\nWhen the url " + url + " was requested, this error was received: \n" + getStackTrace( ioe ) + "\n");
1154    } finally {
1155      if ( in != null ) {
1156        try { in.close(); }
1157        catch (Exception e) {}
1158      }
1159      if ( isr != null ) {
1160        try { isr.close(); }
1161        catch (Exception e) {}
1162      }
1163    }
1164    return results.toString();
1165  }
1166 
1167  /** this method returns the contents of the page specified as the URL.  the
1168   *  URL should be a fully qualified request string.  for example,
1169   *     http://rygar.atg.com:8880/some/directory/page.jhtml
1170   *
1171   *  Unlike it's sister method with the boolean parameter, this method will
1172   *  not throw an exception.
1173   */
1174  public static String accessURL( String pUrl )
1175  {
1176    try {
1177      return accessURL( pUrl, false );
1178    } catch (Exception e) {
1179      return "\nEncountered an unexpected error while trying to retrieve the configuration info." +
1180        "\nWhen the url " + pUrl + " was requested, this error was received: \n" + getStackTrace( e ) + "\n";
1181    }
1182  }
1183 
1184  // ==================== File IO ============================
1185 
1186  /**
1187   * Writes the byte array into the specified file.
1188   *
1189   * @param File pFile the file to write to
1190   * @param byte[] the bytes to write
1191   *
1192   * @exception IOException if an error occurred opening or reading the file.
1193   */
1194  public static void writeFileBytes(File pFile, byte[] pBytes)
1195    throws IOException
1196  {
1197    if ( pBytes == null ) pBytes = new byte[0];
1198    FileOutputStream fos = null;
1199    try {
1200      fos = new FileOutputStream( pFile );
1201      fos.write( pBytes );
1202    }
1203    catch (IOException e) {
1204      throw e;
1205    }
1206    finally {
1207      try { if (fos != null) fos.close (); }
1208      catch (IOException exc) {}
1209    }
1210  }
1211 
1212  /** converts a delimiter separated String of file names into an
1213   *  array and expands all System property variables in the Strings.
1214   *  it does not check whether resolved file paths exist.
1215   *
1216   *  @param String delimited string of files to be converted to array.
1217   *  @param String delimiter string used to separated files
1218   *  @return String[] array of expanded paths
1219   *  @exception Exception if files can't be resolved properly
1220   */
1221  public static String[] convertFileArray( String pFiles, String pDelimiter )
1222    throws Exception
1223  {
1224    return convertFileArray( pFiles, pDelimiter, null );
1225  }
1226        
1227  /** converts a delimiter separated String of file names into an array
1228   *  and expands all variables in the Strings.  it does not check whether
1229   *  resolved file paths exist.
1230   *
1231   *  @param String delimited string of files to be converted to array.
1232   *  @param String delimiter string used to separated files
1233   *  @param Properties optional primary mapping of key/value pairs to
1234   *  substitute into file paths whererever the syntax <tt>{...}</tt>
1235   *  is found.  If parameter is null, or mapping not found, then
1236   *  System.getProperties() is checked.
1237   *  @return String[] array of expanded paths
1238   *  @exception Exception if files can't be resolved properly
1239   */
1240  public static String[] convertFileArray(String pFiles, String pDelimiter,
1241                                          Properties pPrimaryMapping )
1242    throws Exception
1243  {
1244    if ( pDelimiter == null ) pDelimiter = "";
1245    StringTokenizer st = new StringTokenizer( pFiles, pDelimiter );
1246    List<String> files = new LinkedList<String>();
1247    while ( st.hasMoreTokens() ) {
1248      files.add( expand(st.nextToken(), pPrimaryMapping) );
1249    }
1250    return (String[]) files.toArray( new String[files.size()] );
1251  }
1252 
1253  /** expands all System property variables specified in the supplied
1254   *  String using curly braces syntax <tt>{...}</tt> and returns the
1255   *  resulting String.
1256   *
1257   *  @param String the string to expand.  
1258   *  @exception Exception if a System property resolves to null or if
1259   *  the enclosing braces are not properly matched.
1260   */
1261  public static String expand( String pString )
1262    throws Exception
1263  {
1264    return expand( pString, null );
1265  }
1266 
1267  /** expands all property variables specified in the supplied String
1268   *  using curly braces syntax <tt>{...}</tt> and returns the
1269   *  resulting String.  Property names inside the curly braces can be
1270   *  either a simple String referring to a Java System property, such
1271   *  as "SystemProperty.X", or can be in AppModuleResource format,
1272   *  such as
1273   *  "appModuleResource?moduleID=MyModule&resource=my/resource/file".
1274   *
1275   *  @param String the string to expand.  
1276   *  @param Properties an optional primary key/value mapping to use
1277   *  for System property substitutions.  If param is null, or if
1278   *  mapping not found, then System.getProperties().getProperty(xxx)
1279   *  is used.
1280   *  @return String the expanded string.
1281   *  @exception Exception if a System or AppModuleResource property
1282   *  resolves to null or if the enclosing braces are not properly
1283   *  matched.
1284   */
1285  public static String expand( String pString, Properties pPrimaryMapping )
1286    throws Exception
1287  {
1288    int idx = pString.indexOf("{");
1289    while ( idx != -1 ) {
1290      int end = pString.indexOf("}");
1291      if ( end == -1 )
1292        throw new Exception("Unclosed braces in String " + pString );
1293      String pname = pString.substring(idx+1,end);
1294      String prop = null;
1295      if ( pPrimaryMapping != null ) prop = pPrimaryMapping.getProperty(pname);
1296      if ( prop == null ) {
1297        if ( pname.startsWith("appModuleResource?") )
1298          prop = resolveAppModuleResourceReference(pname).getPath();
1299        // atg.dynamo.root and atg.dynamo.home are resolved specially
1300        // because of BigEar
1301        else if ( pname.equals(ROOT_VAR) ) prop = getDynamoRootDir().getPath();
1302        else if ( pname.equals(HOME_VAR) ) prop = getDynamoHomeDir().getPath();
1303        else prop = System.getProperty(pname);
1304      }
1305      if ( prop == null )
1306        throw new Exception("System property '"
1307                            + pString.substring(idx+1,end)
1308                            + "' is null.  String " + pString
1309                            + " can not be resolved.");
1310 
1311      pString = pString.substring(0,idx) + prop + pString.substring(end+1);
1312      idx = pString.indexOf("{");
1313    }
1314    return pString;
1315  }
1316    
1317  // ===================== atg dynamo info ===================================
1318 
1319  /** product module corresponding to ATG Dynamo */
1320  public static String ATGDYNAMO_PRODUCT_MODULE = "DPS";
1321 
1322  /** specifies the name of the ATG Dynamo product module that will be
1323   *  loaded if Dynamo is being used. */
1324  public static void setAtgDynamoProductModule( String pModule ) {
1325    ATGDYNAMO_PRODUCT_MODULE = pModule;
1326  }
1327 
1328  /** returns the name of the ATG Dynamo product module that will be
1329   *  loaded if Dynamo is being used. */
1330  public static String getAtgDynamoProductModule() {
1331    return ATGDYNAMO_PRODUCT_MODULE;
1332  }
1333    
1334  /** returns an AppModule corresponding to the ATG Dynamo if that
1335   *  product is loaded.  If it isn't loaded then returns null.
1336   */
1337  public static AppModule getAtgDynamoModule() 
1338  {        
1339    // get all modules that were started with dynamo
1340    Iterator<?> modules = getAppLauncher().getModules().iterator();
1341                
1342    while ( modules.hasNext() ) {
1343      AppModule module = (AppModule)modules.next();
1344      if ( module.getName().equals( getAtgDynamoProductModule() ) )
1345        return module;
1346    }
1347                
1348    return null;
1349  }
1350    
1351  // ==================== atg j2ee server info ==============================
1352 
1353  /** product module corresponding to ATG's J2EE Server */
1354  public static String ATGJ2EESERVER_PRODUCT_MODULE = "J2EEServer";
1355 
1356  /** specifies the name of the ATG J2EE Server product module that
1357   *  will be loaded if ATG's J2EE Server is being used. */
1358  public static void setAtgJ2eeServerProductModule( String pModule ) {
1359    ATGJ2EESERVER_PRODUCT_MODULE = pModule;
1360  }
1361 
1362  /** returns the name of the ATG J2EE Server product module that will
1363   *  be loaded if ATG's J2EE Server is being used. */
1364  public static String getAtgJ2eeServerProductModule() {
1365    return ATGJ2EESERVER_PRODUCT_MODULE;
1366  }
1367        
1368  /** returns an AppModule corresponding to the ATG J2EE Server if
1369   *  that product is loaded.  If it isn't loaded then returns null.
1370   */
1371  public static AppModule getAtgJ2eeServerModule() 
1372  {        
1373    // get all modules that were started with dynamo
1374    Iterator<?> modules = getAppLauncher().getModules().iterator();
1375                
1376    while ( modules.hasNext() ) {
1377      AppModule module = (AppModule)modules.next();
1378      if ( module.getName().equals( getAtgJ2eeServerProductModule() ) )
1379        return module;
1380    }
1381                
1382    return null;
1383  }
1384        
1385  // ==================== application info ============================
1386        
1387  /** possible application product modules that may be installed */
1388  public static String[] APPLICATION_PRODUCT_MODULES = {"ACA","ABTest","DCS-SO","CAF"};
1389 
1390  /** specifies the names of possible application product modules that
1391   *  may be installed in Dyanmo.  used to help report on which
1392   *  application modules are running. */
1393  public void setApplicationProductModules( String[] pModules ) {
1394    APPLICATION_PRODUCT_MODULES = pModules;
1395  }
1396 
1397  /** returns the names of possible application product modules that
1398   *  may be installed in Dyanmo.  used to help report on which
1399   *  application modules are running.  NOTE: This method should not
1400   *  be called.  It is only provided so we can specify application
1401   *  modules in a .properties file.  Java classes should call method
1402   *  getApplicationModules().*/
1403  public String[] getApplicationProductModules() {
1404    return APPLICATION_PRODUCT_MODULES;
1405  }
1406                
1407  /** returns an array of AppModule items corresponding to the
1408   * currently running application products.
1409   */
1410  public static AppModule[] getApplicationModules() 
1411  {
1412    List<AppModule> apps = new LinkedList<AppModule>();
1413                
1414    // get all modules that were started with dynamo
1415    Iterator<?> modules = getAppLauncher().getModules().iterator();
1416                
1417    while ( modules.hasNext() ) {
1418      AppModule module = (AppModule)modules.next();
1419      for ( int i=0; i<APPLICATION_PRODUCT_MODULES.length; i++ ) {
1420        // in order to work around bug 80207, we allow a colon ":" in
1421        // the specified module names.  if a colon exists, the name
1422        // before the colon is the name of the module that would be
1423        // started if the application is running.  the name after the
1424        // colon is the module containing the MANIFEST.MF file with
1425        // build info.  if there is no colon, assume the two modules
1426        // are the same.
1427        int idx = APPLICATION_PRODUCT_MODULES[i].indexOf(":");
1428        if ( idx == -1 ) {
1429          // no colon...
1430          if ((APPLICATION_PRODUCT_MODULES[i]).equals(module.getName()))
1431            apps.add( module );
1432        } else {
1433          if (APPLICATION_PRODUCT_MODULES[i].substring(0,idx).equals(module.getName())) {
1434            // NOTE: getAppLauncher().getModule(...) will return a
1435            // module as long as it exists; the module does not need
1436            // to be running.
1437            try {
1438              AppModule mod = getAppLauncher().getModule(APPLICATION_PRODUCT_MODULES[i].substring(idx+1));
1439              log.info("\nMod: " + mod );
1440              if ( mod != null ) apps.add( mod );
1441              else throw new Exception(APPLICATION_PRODUCT_MODULES[i].substring(idx+1) + " not found.");
1442            } catch (Exception ale) {
1443              log.info("*** WARNING [atg.junit.nucleus.TestUtils] "
1444                                 + "Can not resolve module '"
1445                                 + APPLICATION_PRODUCT_MODULES[i].substring(idx+1)
1446                                 + "'. "
1447                                 + ale.getMessage() );
1448            }
1449          }
1450        }
1451      }
1452    }
1453                
1454    return (AppModule[]) apps.toArray( new AppModule[ apps.size() ] );
1455  }
1456 
1457  // =========== generic AppModule info retrieval methods ====================
1458        
1459  private static AppLauncher mAppLauncher = null;
1460 
1461  /** Returns the AppLauncher used to load this class.  */
1462  private static AppLauncher getAppLauncher()
1463  {
1464    if ( mAppLauncher == null )
1465      mAppLauncher = AppLauncher.getAppLauncher( TestUtils.class );
1466    return mAppLauncher;
1467  }
1468        
1469  /** Retrieves a File resource from a Dynamo Module.  Note that the
1470   *  module does not need to be started, it simply has to be
1471   *  installed in the Dynamo.  Returned file is <u>not</u> verified
1472   *  to exist.
1473   * 
1474   *  @param String pModuleName the name of the Dynamo module to look in.  e.g. "SystemTests.JSPTest"
1475   *  @param String pResourceURI the URI of the File to get from the module.  e.g. "mite.xml"
1476   *  @return File the requested file.
1477   **/
1478  public static File getModuleResourceFile(String pModuleName, String pResourceURI ) 
1479  {
1480    return getAppLauncher().getAppModuleManager().getResourceFile(pModuleName, pResourceURI);
1481  }        
1482        
1483  /** Resolves an appModuleResource reference by parsing the string
1484   *  into its constituent ModuleID and ResourceURI.
1485   *  
1486   * @param String pReference The AppModuleResource reference to resolve.  Expected to be of format:
1487   * <br><tt>appModuleResource?moduleID=<i>moduleID</i>&resourceURI=<i>some/URI</i></tt>
1488   * @return File the referenced module resource.
1489   * @exception IllegalArgumentException if the specified reference does not have the proper structure.
1490   */
1491  public static File resolveAppModuleResourceReference( String pReference )
1492  {
1493    // there's probably a standard utility method in Dynamo to do this
1494    // resolution, but i can't find it...
1495    String moduleID = null;
1496    String resourceURI = null;
1497    String ref = pReference;
1498    try {
1499      int idx = ref.indexOf("moduleID=");       // locate moduleID delimiter
1500      if ( idx == -1 ) throw new Exception();
1501      ref = ref.substring( idx + 9 );  // strip up to and including 'moduleID='
1502      idx = ref.indexOf("&resourceURI="); // get index of resourceURI delimiter
1503      moduleID = ref.substring( 0,idx );        // extract moduleID
1504      resourceURI = ref.substring( idx + 13 );  // extract resourceURI
1505    } catch (Throwable t) {
1506      throw new IllegalArgumentException("Can not resolve appModuleReference. "
1507                                         + "Illegal reference syntax: "
1508                                         + pReference);
1509    }
1510    return getModuleResourceFile(moduleID, resourceURI);
1511  }
1512        
1513  /** Retrieves a piece of information from the MANIFEST of the
1514   *  supplied AppModule.  Returns null if the specified information
1515   *  can't be found.
1516   */
1517  public static String getManifestInfo( AppModule pModule, String pEntry)
1518  {
1519    return getManifestInfo( pModule.getManifest(), pEntry );
1520  }
1521  /**
1522   * Logs a message using Nucleus.logInfo() if Nucleus is available.
1523   * Otherwise it logs using log.info()
1524   * @param pMessage
1525   */
1526  public static void log (String pMessage) {
1527    Nucleus n = Nucleus.getGlobalNucleus();
1528    if (n != null)
1529      n.logInfo(pMessage);
1530    else
1531      log.info(new java.util.Date() + ":" + pMessage);
1532  }
1533    
1534  /** Retrieves a piece of information from the specified Manifest file.
1535   *  Returns null if the specified information can't be found.
1536   */
1537  public static String getManifestInfo( Manifest pManifest, String pEntry) 
1538  {
1539    // if manifest or entry key is null return null...
1540    if ( pManifest == null || pEntry == null ) return null;
1541 
1542    if ( pManifest.getMainAttributes() == null ) return null;
1543    else return pManifest.getMainAttributes().getValue( pEntry );
1544  }
1545 
1546  /** Returns the ATG product version ("ATG-Version") of the specified module.
1547   *  Returns UNKNOWN_INFO if the product version can't be determined. 
1548   **/
1549  public static String getAtgVersion(AppModule pModule) {
1550    String version = getManifestInfo(pModule, "ATG-Version");
1551    if ( version != null ) return version;
1552    else return UNKNOWN_INFO;
1553  }
1554 
1555  /** Returns the ATG product build number ("ATG-Build") of the
1556   *  specified module.  Returns UNKNOWN_INFO if the build number
1557   *  can't be determined.
1558   **/
1559  public static String getAtgBuildNumber(AppModule pModule) {
1560    String build = getManifestInfo(pModule, "ATG-Build");
1561    if ( build != null ) return build;
1562    else return UNKNOWN_INFO;
1563  }
1564 
1565  /** Returns the ATG patch version ("ATG-Patch-Version") of the
1566   *  specified module.  Returns null if the module's version can be
1567   *  determined, but a patch version can't.  Returns UNKNOWN_INFO if
1568   *  neither the product or patch version can be determined.
1569   **/
1570  public static String getAtgPatchVersion(AppModule pModule) {
1571    String version = getManifestInfo(pModule, "ATG-Patch-Version");
1572    if ( version != null ) return version;
1573    else if (getAtgVersion(pModule).equals(UNKNOWN_INFO)) return UNKNOWN_INFO;
1574    else return null;
1575  }
1576 
1577  /** Returns the ATG patch build number ("ATG-Patch-Build") of the
1578   *  specified module.  Returns null if the module's build number can
1579   *  be determined, but a patch build number can't.  Returns
1580   *  UNKNOWN_INFO if neither the product or patch build number can be
1581   *  determined.
1582   **/
1583  public static String getAtgPatchBuildNumber(AppModule pModule) {
1584    String build = getManifestInfo(pModule, "ATG-Patch-Build");
1585    if ( build != null ) return build;
1586    else if (getAtgBuildNumber(pModule).equals(UNKNOWN_INFO))
1587      return UNKNOWN_INFO;
1588    else return null;
1589  }
1590        
1591  /** Returns the ATG full product version ("ATG-Version-Full") of the
1592   *  specified module.  Returns UNKNOWN_INFO if the full product
1593   *  version can't be determined.
1594   **/
1595  public static String getAtgFullVersion(AppModule pModule) {
1596    String version = getManifestInfo(pModule, "ATG-Version-Full");
1597    if ( version != null ) return version;
1598    else return UNKNOWN_INFO;
1599  }
1600 
1601  // ==================== Dynamo Environment Information =====================
1602        
1603  // some methods called on DynamoEnv are not available in older
1604  // versions of the class, so use reflection to maintain backward
1605  // compatibility.
1606        
1607  private static DynamoEnv mDynamoEnv = null;
1608  private static DynamoEnv dynamoEnv() { 
1609    if ( mDynamoEnv == null ) {
1610      try { mDynamoEnv = (DynamoEnv) DynamoEnv.class.newInstance(); } 
1611      catch (Throwable t) {}
1612    }
1613    return mDynamoEnv;
1614  }
1615        
1616  /** Returns true if Dynamo is running as BigEar; otherwise returns false. */
1617  public static boolean isBigEar() 
1618  {
1619    Boolean isBigEar = (Boolean) invokeMethod(dynamoEnv(), "isBigEar",
1620                                              null, null, Boolean.FALSE );
1621    return isBigEar.booleanValue();
1622  }
1623        
1624  /** Returns true if Dynamo is running as BigEar in standalone mode;
1625   * otherwise returns false. */
1626  public static boolean isBigEarStandalone() 
1627  {
1628    Boolean isStandalone = (Boolean) invokeMethod(dynamoEnv(),
1629                                                  "getStandaloneMode",
1630                                                  null, null, Boolean.FALSE );
1631    return isStandalone.booleanValue();
1632  }        
1633        
1634  /** Returns true is Dynamo is running with liveconfig enabled;
1635   * otherwise returns false. */
1636  public static boolean isLiveconfig()
1637  {
1638    // 'isLiveconfig' is a new method in Koko (pr 88105).  try it, but
1639    // if that doesn't work try the 'getProperty' method that was used
1640    // for ATG 7.0.  finally, if that doesn't work just examine System
1641    // properties as a last check.
1642    Boolean isliveconfig = (Boolean) invokeMethod(dynamoEnv(),
1643                                                  "isLiveconfig",
1644                                                  null, null, null);
1645    if ( isliveconfig == null ) {
1646      // that method didn't work, so try this method - which should
1647      // work in ATG 7
1648      String[] args = { "atg.dynamo.liveconfig" };
1649      String propval = (String) invokeMethod(dynamoEnv(),
1650                                             "getProperty", new Class[]{ String.class }, args, null);
1651      if ( propval != null ) {
1652        isliveconfig = Boolean.valueOf("on".equalsIgnoreCase(propval));
1653      } else {
1654        isliveconfig = Boolean.valueOf("on".equalsIgnoreCase( System.getProperty("atg.dynamo.liveconfig") )); 
1655      } 
1656    }
1657    if ( isliveconfig != null ) return isliveconfig.booleanValue();
1658    else return false;
1659  }
1660        
1661  public static Object invokeMethod(Object pObj, String pMethodName,
1662                                    Class<?>[] pSignature, Object[] pParams,
1663                                    Object pDefault )
1664  {
1665    Object returnval = null;
1666    try {
1667      Method meth = pObj.getClass().getMethod( pMethodName, pSignature );
1668      returnval = meth.invoke( pObj, pParams );
1669      //if ( isLoggingDebug() ) logDebug("Method '" + pMethodName + "'
1670      //invoked - return value: " + returnval);
1671    } catch (Throwable t) {
1672      //if ( isLoggingDebug() ) logDebug("Method '" + pMethodName + "'
1673      //could not be invoked.", t);
1674      returnval = pDefault;
1675    }
1676    return returnval;
1677  }        
1678        
1679} // end of class

[all classes][atg.junit.nucleus]
EMMA 2.0.5312 (C) Vladimir Roubtsov