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
15 package atg.junit.nucleus;
16
17 import java.io.BufferedReader;
18 import java.io.ByteArrayOutputStream;
19 import java.io.File;
20 import java.io.FileOutputStream;
21 import java.io.IOException;
22 import java.io.InputStreamReader;
23 import java.io.PrintStream;
24 import java.lang.reflect.Method;
25 import java.net.InetAddress;
26 import java.net.MalformedURLException;
27 import java.net.URL;
28 import java.net.UnknownHostException;
29 import java.util.Iterator;
30 import java.util.LinkedList;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Properties;
34 import java.util.StringTokenizer;
35 import java.util.jar.Manifest;
36
37 import javax.activation.DataHandler;
38 import javax.activation.FileDataSource;
39 import javax.mail.BodyPart;
40 import javax.mail.Message;
41 import javax.mail.Multipart;
42 import javax.mail.internet.MimeBodyPart;
43 import javax.mail.internet.MimeMultipart;
44
45 import org.apache.log4j.Logger;
46 import org.w3c.dom.Node;
47
48 import atg.applauncher.AppLauncher;
49 import atg.applauncher.AppModule;
50 import atg.nucleus.DynamoEnv;
51 import atg.nucleus.Nucleus;
52 import atg.service.dynamo.LicenseImpl;
53 import atg.service.email.ContentPart;
54 import atg.service.email.EmailEvent;
55 import atg.service.email.MimeMessageUtils;
56 import atg.service.email.SMTPEmailSender;
57 import atg.servlet.ServletUtil;
58
59 /***
60 * This class is used to hold useful utilty methods people may
61 * need when running tests.
62 */
63 public class TestUtils
64 extends atg.nucleus.GenericService
65 {
66
67 private static Logger log = Logger.getLogger(TestUtils.class);
68
69
70
71
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
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
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
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
97 private static final String APP_SERVER = "atg.dynamo.appserver";
98
99
100 private static final String CONFIGURATION_COMPONENT = "/atg/dynamo/Configuration";
101
102
103 private static final String MAILHOST = "mailsvr.atg.com";
104
105
106
107
108
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
268
269
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
366 if ( getAtgJ2eeServerInstallDir() == null ) return true;
367
368
369 else return ( ! getAtgJ2eeServerInstallDir().getCanonicalFile().equals(getDynamoRootDir().getCanonicalFile() ) );
370 } catch ( IOException ioe ) {
371
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
398 return "AppDAP";
399 } else if ( ! version.startsWith("4") && ! version.startsWith("5.0") && ! version.startsWith("5.1") ) {
400
401
402
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
543 File f = new File( getWasHomeDir(), "properties/version/BASE.product" );
544
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
631
632 String startfile = System.getProperty( "java.security.policy" );
633 if ( startfile != null ) {
634
635
636
637 homedir = atg.core.io.FileUtils.getParent( startfile );
638
639 homedir = atg.core.io.FileUtils.getParent( homedir );
640
641 homedir = atg.core.io.FileUtils.getParent( homedir );
642
643 homedir = atg.core.io.FileUtils.getParent( homedir );
644
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
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
678
679
680
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
705
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
721
722
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 <jar> 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
782
783
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
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
834 Message msg = MimeMessageUtils.createMessage( pReturnAddress, pSubject);
835
836 MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
837
838
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
846 EmailEvent em = new EmailEvent(msg);
847
848
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
884 if ( pAddresses == null ||
885 pAddresses.size() <= 0 )
886 return;
887
888
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
923 if ( pAddress == null ||
924 pAddress.trim().length() == 0 )
925 return;
926
927
928 Message msg = MimeMessageUtils.createMessage( pAddress, pSubject);
929
930
931 MimeMessageUtils.setRecipient(msg, Message.RecipientType.TO, pAddress);
932
933
934 Multipart mp = new MimeMultipart();
935
936
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
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
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
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
990 EmailEvent em = new EmailEvent(msg);
991
992
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
1050 if ( pAddresses == null ||
1051 pAddresses.size() <= 0 )
1052 return;
1053
1054
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
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
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
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
1300
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
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
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
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
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
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
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
1421
1422
1423
1424
1425
1426
1427 int idx = APPLICATION_PRODUCT_MODULES[i].indexOf(":");
1428 if ( idx == -1 ) {
1429
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
1435
1436
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
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
1494
1495 String moduleID = null;
1496 String resourceURI = null;
1497 String ref = pReference;
1498 try {
1499 int idx = ref.indexOf("moduleID=");
1500 if ( idx == -1 ) throw new Exception();
1501 ref = ref.substring( idx + 9 );
1502 idx = ref.indexOf("&resourceURI=");
1503 moduleID = ref.substring( 0,idx );
1504 resourceURI = ref.substring( idx + 13 );
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
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
1602
1603
1604
1605
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
1639
1640
1641
1642 Boolean isliveconfig = (Boolean) invokeMethod(dynamoEnv(),
1643 "isLiveconfig",
1644 null, null, null);
1645 if ( isliveconfig == null ) {
1646
1647
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
1670
1671 } catch (Throwable t) {
1672
1673
1674 returnval = pDefault;
1675 }
1676 return returnval;
1677 }
1678
1679 }