1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.tool;
  28 
  29 import java.io.BufferedInputStream;
  30 import java.io.File;
  31 import java.io.FileInputStream;
  32 import java.io.FileNotFoundException;
  33 import java.io.IOException;
  34 import java.io.InputStream;
  35 import java.net.URL;
  36 import java.net.URLClassLoader;
  37 import java.text.NumberFormat;
  38 import java.text.ParsePosition;
  39 import java.util.Iterator;
  40 import java.util.ListIterator;
  41 import java.util.Locale;
  42 import java.util.Map;
  43 import java.util.MissingResourceException;
  44 import java.util.Properties;
  45 import java.util.ResourceBundle;
  46 import java.util.Set;
  47 import java.util.Vector;
  48 
  49 import com.sun.interview.Interview;
  50 import com.sun.interview.NullQuestion;
  51 import com.sun.interview.CompositeQuestion;
  52 import com.sun.interview.Question;
  53 import com.sun.javatest.FileParameters;
  54 import com.sun.javatest.InterviewParameters;
  55 import com.sun.javatest.Parameters;
  56 import com.sun.javatest.Status;
  57 import com.sun.javatest.TestSuite;
  58 import com.sun.javatest.WorkDirectory;
  59 import com.sun.javatest.util.DirectoryClassLoader;
  60 //import com.sun.javatest.util.PathClassLoader;
  61 import com.sun.javatest.util.HelpTree;
  62 import com.sun.javatest.util.I18NResourceBundle;
  63 import java.util.HashMap;
  64 import java.util.Map.Entry;
  65 
  66 /**
  67  * A manager for all the various configuration commands.
  68  */
  69 public class ConfigManager
  70     extends CommandManager
  71 {
  72     public HelpTree.Node getHelp() {
  73         Object[] childData = {
  74             ConcurrencyCommand.getName(),
  75             ConfigCommand.getName(),
  76             EnvCommand.getName(),
  77             EnvFilesCommand.getNames(),
  78             ExcludeListCommand.getName(),
  79             KeywordsCommand.getName(),
  80             KflCommand.getName(),
  81             OpenCommand.getName(),
  82             ParamsCommand.getHelp(),
  83             PriorStatusCommand.getName(),
  84             SetCommand.getName(),
  85             TestsCommand.getName(),
  86             TestSuiteCommand.getNames(),
  87             TimeoutFactorCommand.getName(),
  88             WorkDirectoryCommand.getNames(),
  89             WriteConfigCommand.getName()
  90         };
  91 
  92         return getHelp(i18n, "cnfg", childData);
  93     }
  94 
  95     HelpTree.Node getHelp(I18NResourceBundle i18n, String prefix, Object[] childData) {
  96         Vector<HelpTree.Node> v = new Vector<>();
  97         for (int i = 0; i < childData.length; i++) {
  98             Object data = childData[i];
  99             if (data instanceof HelpTree.Node)
 100                 v.add((HelpTree.Node)data);
 101             else if (data instanceof String)
 102                 v.add(new HelpTree.Node(i18n, prefix + "." + data));
 103             else if (data instanceof String[]) {
 104                 String[] names = (String[]) data;
 105                 for (int j = 0; j < names.length; j++)
 106                     v.add(new HelpTree.Node(i18n, prefix + "." + names[j]));
 107             }
 108             else
 109                 throw new IllegalArgumentException();
 110         }
 111         HelpTree.Node[] childNodes = new HelpTree.Node[v.size()];
 112         v.copyInto(childNodes);
 113         return new HelpTree.Node(i18n, prefix, childNodes);
 114     }
 115 
 116     public boolean parseCommand(String cmd, ListIterator<String> argIter, CommandContext ctx)
 117         throws Command.Fault
 118     {
 119         if (isMatch(cmd, ConcurrencyCommand.getName())) {
 120             ctx.addCommand(new ConcurrencyCommand(argIter));
 121             return true;
 122         }
 123 
 124         if (isMatch(cmd, ConfigCommand.getName())) {
 125             ctx.addCommand(new ConfigCommand(argIter));
 126             return true;
 127         }
 128 
 129         if (isMatch(cmd, EnvCommand.getName())) {
 130             ctx.addCommand(new EnvCommand(argIter));
 131             return true;
 132         }
 133 
 134         if (isMatch(cmd, EnvFilesCommand.getNames())) {
 135             ctx.addCommand(new EnvFilesCommand(argIter));
 136             return true;
 137         }
 138 
 139         if (isMatch(cmd, ExcludeListCommand.getName())) {
 140             ctx.addCommand(new ExcludeListCommand(argIter));
 141             return true;
 142         }
 143 
 144         if (isMatch(cmd, OpenCommand.getName())) {
 145             ctx.addCommand(new OpenCommand(argIter));
 146             return true;
 147         }
 148 
 149         if (isMatch(cmd, KeywordsCommand.getName())) {
 150             ctx.addCommand(new KeywordsCommand(argIter));
 151             return true;
 152         }
 153 
 154         if (isMatch(cmd, KflCommand.getName())) {
 155             ctx.addCommand(new KflCommand(argIter));
 156             return true;
 157         }
 158 
 159         if (isMatch(cmd, ParamsCommand.getName())) {
 160             ctx.addCommand(new ParamsCommand(argIter));
 161             return true;
 162         }
 163 
 164         if (isMatch(cmd, PriorStatusCommand.getName())) {
 165             ctx.addCommand(new PriorStatusCommand(argIter));
 166             return true;
 167         }
 168 
 169         if (isMatch(cmd, SetCommand.getName())) {
 170             ctx.addCommand(new SetCommand(argIter));
 171             return true;
 172         }
 173 
 174         if (isMatch(cmd, SetXCommand.getName())) {
 175             ctx.addCommand(new SetXCommand(argIter));
 176             return true;
 177         }
 178 
 179         if (isMatch(cmd, TestsCommand.getName())) {
 180             ctx.addCommand(new TestsCommand(argIter));
 181             return true;
 182         }
 183 
 184         if (isMatch(cmd, TestSuiteCommand.getNames())) {
 185             ctx.addCommand(new TestSuiteCommand(argIter));
 186             return true;
 187         }
 188 
 189         if (isMatch(cmd, TimeoutFactorCommand.getName())) {
 190             ctx.addCommand(new TimeoutFactorCommand(argIter));
 191             return true;
 192         }
 193 
 194         if (isMatch(cmd, WorkDirectoryCommand.getNames())) {
 195             ctx.addCommand(new WorkDirectoryCommand(argIter));
 196             return true;
 197         }
 198 
 199         if (isMatch(cmd, WriteConfigCommand.getName())) {
 200             ctx.addCommand(new WriteConfigCommand(argIter));
 201             return true;
 202         }
 203 
 204 
 205         return false;
 206     }
 207 
 208     static Command getOpenCommand(File file)
 209         throws Command.Fault
 210     {
 211         return new OpenCommand(file);
 212     }
 213 
 214     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(ConfigManager.class);
 215 
 216     //--------------------------------------------------------------------------
 217 
 218     private static class ConcurrencyCommand extends Command
 219     {
 220         static String getName() {
 221             return "concurrency";
 222         }
 223 
 224         ConcurrencyCommand(ListIterator<String> argIter) throws Fault {
 225             super(getName());
 226 
 227             if (!argIter.hasNext())
 228                 throw new Fault(i18n, "cnfg.conc.missingArg");
 229 
 230             String arg = nextArg(argIter);
 231 
 232             NumberFormat fmt = NumberFormat.getIntegerInstance(); // will be locale-specific
 233             ParsePosition pos = new ParsePosition(0);
 234             Number num = fmt.parse(arg, pos);
 235             if (num != null && (pos.getIndex() == arg.length())) {
 236                 value = num.intValue();
 237                 if (value < Parameters.ConcurrencyParameters.MIN_CONCURRENCY
 238                     || value > Parameters.ConcurrencyParameters.MAX_CONCURRENCY) {
 239                     throw new Fault(i18n, "cnfg.conc.badRange",
 240                                     new Object[] {
 241                                         arg,
 242                                         new Integer(Parameters.ConcurrencyParameters.MIN_CONCURRENCY),
 243                                         new Integer(Parameters.ConcurrencyParameters.MAX_CONCURRENCY) });
 244                 }
 245             }
 246             else
 247                 throw new Fault(i18n, "cnfg.conc.badValue", arg);
 248         }
 249 
 250         public void run(CommandContext ctx) throws Fault {
 251             InterviewParameters p = getConfig(ctx);
 252             if (p.getConcurrencyParameters() instanceof Parameters.MutableConcurrencyParameters) {
 253                 Parameters.MutableConcurrencyParameters cParams =
 254                     (Parameters.MutableConcurrencyParameters) (p.getConcurrencyParameters());
 255                 cParams.setConcurrency(value);
 256             }
 257             else
 258                 throw new Fault(i18n, "cnfg.conc.notEditable");
 259         }
 260 
 261         private int value;
 262     }
 263 
 264 
 265     //--------------------------------------------------------------------------
 266 
 267     private static class ConfigCommand extends Command
 268     {
 269         static String getName() {
 270             return "config";
 271         }
 272 
 273         ConfigCommand(ListIterator<String> argIter) throws Fault {
 274             super(getName());
 275 
 276             if (!argIter.hasNext())
 277                 throw new Fault(i18n, "cnfg.conf.missingArg");
 278 
 279             path = new File(nextArg(argIter));
 280         }
 281 
 282         ConfigCommand(File path) {
 283             super(path.getPath());
 284 
 285             this.path = path;
 286         }
 287 
 288         public void run(CommandContext ctx) throws Fault {
 289             /*OLD
 290             try {
 291                 InterviewParameters p = getConfig(ctx);
 292                 if (p == null)
 293                     ctx.setInterviewParameters(InterviewParameters.open(path));
 294                 else {
 295                     // should check for compatibility?
 296                     p.load(path);
 297                 }
 298 
 299                 if (ctx.getWorkDirectory() == null)
 300                     ctx.setWorkDirectory(p.getWorkDirectory());
 301 
 302                 ctx.setAutoRunReportDir(null);
 303             }
 304             catch (TestSuite.Fault e) {
 305                 throw new Fault(i18n, "cnfg.cantSetParameters", e.getMessage());
 306             }
 307             catch (FileNotFoundException e) {
 308                 throw new Fault(i18n, "cnfg.cantFindFile", path);
 309             }
 310             catch (IOException e) {
 311                 throw new Fault(i18n, "cnfg.cantReadFile", new Object[] { path, e} );
 312             }
 313             catch (InterviewParameters.Fault e) {
 314                 throw new Fault(i18n, "cnfg.cantOpenConfig", new Object[] { path, e} );
 315             }
 316             */
 317 
 318             try {
 319                 ctx.setConfig(path);
 320                 ctx.setAutoRunReportDir(null);
 321             }
 322             catch (CommandContext.Fault e) {
 323                 throw new Fault(e);
 324             }
 325         }
 326 
 327         private File path;
 328     }
 329 
 330     //--------------------------------------------------------------------------
 331 
 332     private static class WriteConfigCommand extends Command
 333     {
 334         static String getName() {
 335             return "writeConfig";
 336         }
 337 
 338         WriteConfigCommand(ListIterator<String> argIter) throws Fault {
 339             super(getName());
 340 
 341             if (!argIter.hasNext())
 342                 throw new Fault(i18n, "cnfg.conf.missingArg");
 343                 // XXX could provide a better error message, perhaps including the value of
 344                 //     getName(), because the missingArg error message is general purpose
 345                 //     EX: throw new Fault(i18n, "cnfg.conf.missingArg", getName());
 346 
 347             path = new File(nextArg(argIter));
 348         }
 349 
 350         WriteConfigCommand(File path) {
 351             super(path.getPath());
 352 
 353             this.path = path;
 354         }
 355 
 356         public void run(CommandContext ctx) throws Fault {
 357             try {
 358                 InterviewParameters p = getConfig(ctx);
 359                 p.saveAs(path, true, true);
 360             }
 361             catch (IOException e) {
 362                 if (!path.canWrite())
 363                     throw new Fault(i18n, "cnfg.writeConfig.cantWrite", path.getPath());
 364                 else
 365                     throw new Fault(i18n, "cnfg.writeConfig.writeErr", new Object[] { path, e } );
 366             }
 367             catch (Interview.Fault e) {
 368                 throw new Fault(i18n, "cnfg.writeConfig.badConfig", new Object[] { path, e.getMessage() } );
 369             }   // catch
 370         }
 371 
 372         private File path;
 373     }
 374 
 375     //--------------------------------------------------------------------------
 376 
 377     private static class EnvCommand extends Command
 378     {
 379         static String getName() {
 380             return "env";
 381         }
 382 
 383         EnvCommand(ListIterator<String> argIter) throws Fault {
 384             super(getName());
 385 
 386             if (!argIter.hasNext())
 387                 throw new Fault(i18n, "cnfg.env.missingArg");
 388 
 389             name = nextArg(argIter);
 390         }
 391 
 392         public void run(CommandContext ctx) throws Fault {
 393             InterviewParameters p = getConfig(ctx);
 394             if (p.getEnvParameters() instanceof Parameters.LegacyEnvParameters) {
 395                 Parameters.LegacyEnvParameters eParams =
 396                     (Parameters.LegacyEnvParameters) (p.getEnvParameters());
 397                 eParams.setEnvName(name);
 398             }
 399             else
 400                 throw new Fault(i18n, "cnfg.env.notEditable");
 401         }
 402 
 403         private String name;
 404     }
 405 
 406     //--------------------------------------------------------------------------
 407 
 408     private static class EnvFilesCommand extends Command
 409     {
 410         static String[] getNames() {
 411             return new String[] { "envfile", "envfiles" };
 412         }
 413 
 414         EnvFilesCommand(ListIterator<String> argIter) throws Fault {
 415             super(getNames()[0]);
 416 
 417             Vector<File> v = new Vector<>();
 418 
 419             while (argIter.hasNext()) {
 420                 String arg = nextArg(argIter);
 421                 if (arg.startsWith("-")) {
 422                     putbackArg(argIter);
 423                     break;
 424                 }
 425                 else
 426                     v.add(new File(arg));
 427             }
 428 
 429             if (v.size() == 0)
 430                 throw new Fault(i18n, "cnfg.envFiles.noFiles");
 431 
 432             files = new File[v.size()];
 433             v.toArray(files);
 434         }
 435 
 436         public void run(CommandContext ctx) throws Fault {
 437             InterviewParameters p = getConfig(ctx);
 438             if (p.getEnvParameters() instanceof Parameters.LegacyEnvParameters) {
 439                 Parameters.LegacyEnvParameters eParams =
 440                     (Parameters.LegacyEnvParameters) (p.getEnvParameters());
 441                 eParams.setEnvFiles(files);
 442             }
 443             else
 444                 throw new Fault(i18n, "cnfg.envFiles.notEditable");
 445         }
 446 
 447         private File[] files;
 448     }
 449 
 450     //--------------------------------------------------------------------------
 451 
 452     private static class ExcludeListCommand extends Command
 453     {
 454         static String getName() {
 455             return "excludeList";
 456         }
 457 
 458         ExcludeListCommand(ListIterator<String> argIter) throws Fault {
 459             super(getName());
 460 
 461             // in time, we should support -none, -default, -latest etc
 462             Vector<File> v = new Vector<>();
 463 
 464             while (argIter.hasNext()) {
 465                 String arg = nextArg(argIter);
 466                 if (arg.startsWith("-")) {
 467                     putbackArg(argIter);
 468                     break;
 469                 }
 470                 else
 471                     v.add(new File(arg));
 472             }
 473 
 474             if (v.size() == 0)
 475                 throw new Fault(i18n, "cnfg.excl.noFiles");
 476 
 477             files = new File[v.size()];
 478             v.toArray(files);
 479         }
 480 
 481         public void run(CommandContext ctx) throws Fault {
 482             InterviewParameters p = getConfig(ctx);
 483             if (p.getExcludeListParameters() instanceof Parameters.MutableExcludeListParameters) {
 484                 Parameters.MutableExcludeListParameters eParams =
 485                     (Parameters.MutableExcludeListParameters) (p.getExcludeListParameters());
 486                 eParams.setExcludeMode(Parameters.MutableExcludeListParameters.CUSTOM_EXCLUDE_LIST);
 487                 eParams.setCustomExcludeFiles(files);
 488             }
 489             else
 490                 throw new Fault(i18n, "cnfg.excl.notEditable");
 491         }
 492 
 493         private File[] files;
 494     }
 495     //--------------------------------------------------------------------------
 496 
 497     private static class KflCommand extends Command
 498     {
 499         static String getName() {
 500             return "kfl";
 501         }
 502 
 503         KflCommand(ListIterator<String> argIter) throws Fault {
 504             super(getName());
 505 
 506             // in time, we should support -none, -default, -latest etc
 507             Vector<File> v = new Vector<>();
 508 
 509             while (argIter.hasNext()) {
 510                 String arg = nextArg(argIter);
 511                 if (arg.startsWith("-")) {
 512                     putbackArg(argIter);
 513                     break;
 514                 }
 515                 else
 516                     v.add(new File(arg));
 517             }
 518 
 519             if (v.size() == 0)
 520                 throw new Fault(i18n, "cnfg.kfl.noFiles");
 521 
 522             files = new File[v.size()];
 523             v.toArray(files);
 524         }
 525 
 526         public void run(CommandContext ctx) throws Fault {
 527             InterviewParameters p = getConfig(ctx);
 528             p.setKnownFailureFiles(files);
 529 //          if (p.getExcludeListParameters() instanceof Parameters.MutableExcludeListParameters) {
 530 //              Parameters.MutableExcludeListParameters eParams =
 531 //                  (Parameters.MutableExcludeListParameters) (p.getExcludeListParameters());
 532 //              eParams.setExcludeMode(Parameters.MutableExcludeListParameters.CUSTOM_EXCLUDE_LIST);
 533 //              eParams.setCustomExcludeFiles(files);
 534 //          }
 535 //          else
 536 //              throw new Fault(i18n, "cnfg.excl.notEditable");
 537         }
 538 
 539         private File[] files;
 540     }
 541     //--------------------------------------------------------------------------
 542 
 543     private static class OpenCommand extends Command
 544     {
 545         static String getName() {
 546             return "open";
 547         }
 548 
 549         OpenCommand(File file) throws Fault {
 550             super(file.getPath());
 551             cmdForFile = getCommandForFile(file);
 552         }
 553 
 554         OpenCommand(ListIterator<String> argIter) throws Fault {
 555             super(getName());
 556 
 557             if (!argIter.hasNext())
 558                 throw new Fault(i18n, "cnfg.open.missingArg");
 559 
 560             String arg = nextArg(argIter);
 561             cmdForFile = getCommandForFile(new File(arg));
 562         }
 563 
 564         public void run(CommandContext ctx) throws Fault {
 565             cmdForFile.run(ctx);
 566         }
 567 
 568         Command getCommandForFile(File file)
 569             throws Fault
 570         {
 571             if (!file.exists())
 572                 throw new Fault(i18n, "cnfg.open.cantFindFile", file);
 573 
 574             if (TestSuite.isTestSuite(file))
 575                 return new TestSuiteCommand(file);
 576 
 577             if (WorkDirectory.isWorkDirectory(file))
 578                 return new WorkDirectoryCommand(file);
 579 
 580             if (FileParameters.isParameterFile(file))
 581                 return new ParamFileCommand(file);
 582 
 583             if (InterviewParameters.isInterviewFile(file))
 584                 return new ConfigCommand(file);
 585 
 586             if (file.getPath().endsWith(".jte"))
 587                 throw new Fault(i18n, "cnfg.open.cantOpenJTE", file);
 588 
 589             if (file.getPath().endsWith(".jtt"))
 590                 throw new Fault(i18n, "cnfg.open.cantOpenJTT", file);
 591 
 592             if (file.getPath().endsWith(".jtx"))
 593                 throw new Fault(i18n, "cnfg.open.cantOpenJTX", file);
 594 
 595             throw new Fault(i18n, "cnfg.open.unknownFileType", file);
 596         }
 597 
 598         private Command cmdForFile;
 599     }
 600 
 601     //--------------------------------------------------------------------------
 602 
 603     private static class KeywordsCommand extends Command
 604     {
 605         static String getName() {
 606             return "keywords";
 607         }
 608 
 609         KeywordsCommand(ListIterator<String> argIter) throws Fault {
 610             super(getName());
 611 
 612             // could support -all -any
 613             if (!argIter.hasNext())
 614                 throw new Fault(i18n, "cnfg.keywords.missingArg");
 615 
 616             expr = nextArg(argIter);
 617         }
 618 
 619         public void run(CommandContext ctx) throws Fault {
 620             InterviewParameters p = getConfig(ctx);
 621             if (p.getKeywordsParameters() instanceof Parameters.MutableKeywordsParameters) {
 622                 Parameters.MutableKeywordsParameters kParams =
 623                     (Parameters.MutableKeywordsParameters) (p.getKeywordsParameters());
 624                 if (expr == null)
 625                     kParams.setKeywordsMode(Parameters.MutableKeywordsParameters.NO_KEYWORDS);
 626                 else {
 627                     kParams.setKeywordsMode(Parameters.MutableKeywordsParameters.MATCH_KEYWORDS);
 628                     kParams.setMatchKeywords(Parameters.MutableKeywordsParameters.EXPR, expr);
 629                 }
 630             }
 631             else
 632                 throw new Fault(i18n, "cnfg.keywords.notEditable");
 633         }
 634 
 635         private String expr;
 636     }
 637 
 638     //--------------------------------------------------------------------------
 639     // Legacy CLI support (-params, jte and jtp files)
 640     // Very deprecated.
 641 
 642     private static abstract class ParamsBaseCommand extends Command
 643     {
 644         ParamsBaseCommand(String name) {
 645             super(name);
 646         }
 647 
 648         protected void setParameters(CommandContext ctx, FileParameters fp)
 649             throws Fault
 650         {
 651             /*OLD
 652               if (ctx.getTestSuite() != null)
 653               throw new Command.Fault(i18n, "cnfg.testSuiteAlreadySet");
 654 
 655               if (ctx.getWorkDirectory() != null)
 656               throw new Command.Fault(i18n, "cnfg.workDirAlreadySet");
 657             */
 658 
 659             try {
 660                 ctx.setTestSuite(fp.getTestSuite());
 661 
 662                 if (fp.getWorkDirectory() != null)
 663                     ctx.setWorkDirectory(fp.getWorkDirectory());
 664 
 665                 getConfig(ctx).load(fp);
 666 
 667                 // support for old feature
 668                 File autoRunReportDir = fp.getReportDir();
 669                 if (autoRunReportDir == null) {
 670                     File rd = new File("reports", "report");
 671                     autoRunReportDir = ctx.getWorkDirectory().getFile(rd.getPath());
 672                 }
 673                 ctx.setAutoRunReportDir(autoRunReportDir);
 674             }
 675             catch (TestSuite.Fault e) {
 676                 throw new Fault(i18n, "cnfg.cantSetParameters", e.getMessage());
 677             }
 678             catch (CommandContext.Fault e) {
 679                 throw new Fault(e);
 680             }
 681         }
 682     }
 683 
 684     //--------------------------------------------------------------------------
 685 
 686     private static class ParamFileCommand extends ParamsBaseCommand
 687     {
 688         ParamFileCommand(File path) {
 689             super(path.getPath());
 690             this.path = path;
 691         }
 692 
 693         public void run(CommandContext ctx) throws Fault {
 694             try {
 695                 FileParameters params = new FileParameters(path);
 696                 if (!params.isValid()) {
 697                     throw new Fault(i18n, "cnfg.params.badParameterFile",
 698                                     new Object[] { path, params.getErrorMessage() } );
 699                 }
 700                 setParameters(ctx, params);
 701             }
 702             catch (FileNotFoundException e) {
 703                 throw new Fault(i18n, "cnfg.params.cantFindFile", path);
 704             }
 705             catch (IOException e) {
 706                 throw new Fault(i18n, "cnfg.params.cantReadFile",
 707                                 new Object[] { path, e } );
 708             }
 709         }
 710 
 711         private File path;
 712     }
 713 
 714     //--------------------------------------------------------------------------
 715 
 716     private static class ParamsCommand extends ParamsBaseCommand
 717     {
 718         static String getName() {
 719             return "params";
 720         }
 721 
 722         static HelpTree.Node getHelp() {
 723             String[] opts = {
 724                 "testSuite", "t",
 725                 "keywords",
 726                 "status",
 727                 "exclude",
 728                 "envfile",
 729                 "env",
 730                 "conc",
 731                 "timeout",
 732                 "report", "r",
 733                 "workdir", "w"
 734             };
 735             return new HelpTree.Node(i18n, "cnfg.params", opts);
 736         }
 737 
 738         ParamsCommand(ListIterator<String> argIter) throws Fault {
 739             super(getName());
 740 
 741             Vector<String> v = new Vector<>();
 742             while (argIter.hasNext())
 743                 v.add(nextArg(argIter));
 744             String[] args = new String[v.size()];
 745             v.copyInto(args);
 746 
 747             try {
 748                 params = new FileParameters(args);
 749             } catch (IllegalArgumentException e) {
 750                 throw new Fault(i18n, "cnfg.params.badValue", e.getMessage());
 751             }
 752 
 753             if (!params.isValid())
 754                 throw new Fault(i18n, "cnfg.params.badValue", params.getErrorMessage());
 755         }
 756 
 757         public void run(CommandContext ctx) throws Fault {
 758             setParameters(ctx, params);
 759         }
 760 
 761         private FileParameters params;
 762     }
 763 
 764     //--------------------------------------------------------------------------
 765 
 766     private static class PriorStatusCommand extends Command
 767     {
 768         static String getName() {
 769             return "priorStatus";
 770         }
 771 
 772         PriorStatusCommand(ListIterator<String> argIter) throws Fault {
 773             super(getName());
 774 
 775             if (!argIter.hasNext())
 776                 throw new Fault(i18n, "cnfg.status.missingArg");
 777 
 778             String arg = nextArg(argIter);
 779             String[] words = split(arg.toLowerCase());
 780             boolean any = false;
 781             values = new boolean[Status.NUM_STATES];
 782             if (words != null) {
 783                 for (int i = 0; i < words.length; i++) {
 784                     String w = words[i];
 785                     if (w.startsWith("pass")) {
 786                         values[Status.PASSED] = any = true;
 787                     }
 788                     else if (w.startsWith("fail")) {
 789                         values[Status.FAILED] = any = true;
 790                     }
 791                     else if (w.startsWith("error")) {
 792                         values[Status.ERROR] = any = true;
 793                     }
 794                     else if (w.startsWith("notrun")) {
 795                         values[Status.NOT_RUN] = any = true;
 796                     }
 797                     else
 798                         throw new Fault(i18n, "cnfg.status.badArg", w);
 799                 }
 800             }
 801 
 802 
 803             if (!any)
 804                 throw new Fault(i18n, "cnfg.status.noValues");
 805         }
 806 
 807         public void run(CommandContext ctx) throws Fault {
 808             InterviewParameters p = getConfig(ctx);
 809             if (p.getPriorStatusParameters() instanceof Parameters.MutablePriorStatusParameters) {
 810                 Parameters.MutablePriorStatusParameters sParams =
 811                     (Parameters.MutablePriorStatusParameters) (p.getPriorStatusParameters());
 812                 sParams.setPriorStatusMode(Parameters.MutablePriorStatusParameters.MATCH_PRIOR_STATUS);
 813                 sParams.setMatchPriorStatusValues(values);
 814             }
 815             else
 816                 throw new Fault(i18n, "cnfg.status.notEditable");
 817         }
 818 
 819         private static String[] split(String s) {
 820             if (s == null)
 821             return null;
 822 
 823             Vector<String> v = new Vector<>();
 824             int start = -1;
 825             for (int i = 0; i < s.length(); i++) {
 826                 if (Character.isLetterOrDigit(s.charAt(i))) {
 827                     if (start == -1)
 828                         start = i;
 829                 }
 830                 else {
 831                     if (start != -1)
 832                         v.addElement(s.substring(start, i));
 833                     start = -1;
 834                 }
 835             }
 836             if (start != -1)
 837             v.addElement(s.substring(start));
 838             if (v.size() == 0)
 839             return null;
 840             String[] a = new String[v.size()];
 841             v.copyInto(a);
 842             return a;
 843         }
 844 
 845         private boolean[] values;
 846     }
 847 
 848 
 849     //--------------------------------------------------------------------------
 850 
 851     private static class SetCommand extends Command
 852     {
 853         static String getName() {
 854             return "set";
 855         }
 856 
 857         SetCommand(ListIterator<String> argIter) throws Fault {
 858             super(getName());
 859 
 860             if (!argIter.hasNext())
 861                 throw new Fault(i18n, "cnfg.set.insufficientArgs");
 862 
 863             String arg = nextArg(argIter);
 864             if (arg.equals("-f") || arg.equals("-file")) {
 865                 if (!argIter.hasNext())
 866                     throw new Fault(i18n, "cnfg.set.insufficientArgs");
 867                 file = new File(nextArg(argIter));
 868             }
 869             else {
 870                 tag = arg;
 871                 if (!argIter.hasNext())
 872                     throw new Fault(i18n, "cnfg.set.insufficientArgs");
 873                 value = nextArg(argIter);
 874             }
 875         }
 876 
 877         public void run(CommandContext ctx) throws Fault {
 878             InterviewParameters p = getConfig(ctx);
 879             Question[] path = p.getPath();
 880             if (file != null) {
 881                 Map<String, String> values = loadFile(file);
 882                 for (int i = 0; i < path.length; i++) {
 883                     Question q = path[i];
 884                     String v = (values.get(q.getTag()));
 885                     if (v != null) {
 886                         setValue(q, v);
 887                         path = p.getPath();
 888                     }
 889                 }
 890             }
 891             else {
 892                 for (int i = 0; i < path.length; i++) {
 893                     Question q = path[i];
 894                     if (q.getTag().equals(tag)) {
 895                         setValue(q, value);
 896                         return;
 897                     }
 898                 }
 899 
 900                 // The following is not ideal but works for now.
 901                 // It is arguably bad form to return such a long detail
 902                 // string, rather than providing an extra method
 903                 // to generate the trace if required -- i.e. the Fault
 904                 // equivalent of e.printStackTrace()
 905                 throw new Fault(i18n, "cnfg.set.tagNotFound",
 906                                 new Object[] { tag, getPathTrace(path) });
 907             }
 908         }
 909 
 910         private void setValue(Question q, String value) throws Fault {
 911             try {
 912                 if (q instanceof CompositeQuestion) {
 913                     CompositeQuestion cq = (CompositeQuestion)q;
 914                     int sepIndex = value.indexOf(":");
 915                     if (sepIndex > 0) {
 916                         // decode value and send to question
 917                         // could be handled differently in the future
 918                         // text to the left of the colon in the values is the key
 919                         // all text to the right is the value
 920                         String key = value.substring(0, sepIndex);
 921                         String val;
 922                         if (sepIndex == value.length() + 1)
 923                             // handles key:
 924                             val = "";
 925                         else
 926                             // handles key:value
 927                             val = value.substring(sepIndex + 1);
 928 
 929                         cq.setValue(key, val);
 930                     }
 931                     else {
 932                         q.setValue(value);
 933                     }
 934                 }
 935                 else {
 936                     q.setValue(value);
 937                 }
 938             }
 939             catch (InterviewParameters.Fault e) {
 940                 throw new Fault(i18n, "cnfg.set.cantSetValue",
 941                                 new Object[] { q.getTag(), value, e.getMessage() });
 942             }
 943         }
 944 
 945         private static String getPathTrace(Question[] path) {
 946             String lineSep = System.getProperty("line.separator");
 947             StringBuffer sb = new StringBuffer();
 948             for (int i = 0; i < path.length; i++) {
 949                 Question q = path[i];
 950                 sb.append(q.getTag());
 951                 if (!(q instanceof NullQuestion)) {
 952                     String s = q.getStringValue();
 953                     sb.append(" (");
 954                     if (s == null)
 955                         sb.append("null");
 956                     else if (s.length() < 32)
 957                         sb.append(s);
 958                     else {
 959                         sb.append(s.substring(0, 32));
 960                         sb.append("...");
 961                     }
 962                     sb.append(")");
 963                 }
 964                 sb.append(lineSep); // arguably better to do it later when printing to terminal
 965             }
 966             return (sb.toString());
 967         }
 968 
 969         private Map<String, String> loadFile(File file) throws Fault {
 970             try (FileInputStream fis = new FileInputStream(file);
 971                  InputStream in = new BufferedInputStream(fis)) {
 972                 return com.sun.javatest.util.Properties.load(in);
 973             }
 974             catch (FileNotFoundException e) {
 975                 throw new Fault(i18n, "cnfg.set.cantFindFile", file);
 976             }
 977             catch (IOException e) {
 978                 throw new Fault(i18n, "cnfg.set.cantReadFile",
 979                                 new Object[] { file, e.getMessage() });
 980             }
 981         }
 982 
 983         private File file;
 984         private String tag;
 985         private String value;
 986     }
 987 
 988     //--------------------------------------------------------------------------
 989 
 990     /**
 991      * Sets "external" interview values from the command line.
 992      */
 993     private static class SetXCommand extends Command
 994     {
 995         static String getName() {
 996             return "setX";
 997         }
 998 
 999         SetXCommand(ListIterator<String> argIter) throws Fault {
1000             super(getName());
1001 
1002             if (!argIter.hasNext())
1003                 throw new Fault(i18n, "cnfg.set.insufficientArgs");
1004 
1005             String arg = nextArg(argIter);
1006             if (arg.equals("-f") || arg.equals("-file")) {
1007                 if (!argIter.hasNext())
1008                     throw new Fault(i18n, "cnfg.set.insufficientArgs");
1009                 file = new File(nextArg(argIter));
1010             }
1011             else {
1012                 name = arg;
1013                 if (!argIter.hasNext())
1014                     throw new Fault(i18n, "cnfg.set.insufficientArgs");
1015                 value = nextArg(argIter);
1016             }
1017         }
1018 
1019         public void run(CommandContext ctx) throws Fault {
1020             InterviewParameters p = getConfig(ctx);
1021             if (file != null) {
1022                 Map<String, String> values = loadFile(file);
1023                 Set<String> keys = values.keySet();
1024                 Iterator<String> it = keys.iterator();
1025                 String name = null;
1026                 for (int i = 0; it.hasNext(); i++) {
1027                     name = it.next();
1028                     /*  could do it this way to reject unknown props
1029                     String v = p.retrieveProperty(name);
1030                     if (v != null) {
1031                         p.storeProperty(name, (String)(values.get(name)));
1032                     }
1033                     */
1034                     p.storeProperty(name, (values.get(name)));
1035                 }
1036             }
1037             else {
1038                 p.storeProperty(name, value);
1039             }
1040         }
1041 
1042         private Map<String, String> loadFile(File file) throws Fault {
1043             try (FileInputStream fis = new FileInputStream(file);
1044                 InputStream in = new BufferedInputStream(fis)) {
1045                 return com.sun.javatest.util.Properties.load(in);
1046             }
1047             catch (FileNotFoundException e) {
1048                 throw new Fault(i18n, "cnfg.set.cantFindFile", file);
1049             }
1050             catch (IOException e) {
1051                 throw new Fault(i18n, "cnfg.set.cantReadFile",
1052                                 new Object[] { file, e.getMessage() });
1053             }
1054         }
1055 
1056         private File file;
1057         private String name;
1058         private String value;
1059     }
1060 
1061     //--------------------------------------------------------------------------
1062 
1063     private static class TestsCommand extends Command
1064     {
1065         static String getName() {
1066             return "tests";
1067         }
1068 
1069         TestsCommand(ListIterator<String> argIter) throws Fault {
1070             super(getName());
1071 
1072             Vector<String> v = new Vector<>();
1073 
1074             while (argIter.hasNext()) {
1075                 // could possibly support @file or similar syntax here for a list of tests
1076                 String arg = nextArg(argIter);
1077                 if (arg.startsWith("-")) {
1078                     putbackArg(argIter);
1079                     break;
1080                 }
1081                 else
1082                     v.add(arg);
1083             }
1084 
1085             if (v.size() == 0)
1086                 throw new Fault(i18n, "cnfg.tests.noTests");
1087 
1088             tests = new String[v.size()];
1089             v.toArray(tests);
1090         }
1091 
1092         public void run(CommandContext ctx) throws Fault {
1093             InterviewParameters p = getConfig(ctx);
1094             if (p.getTestsParameters() instanceof Parameters.MutableTestsParameters) {
1095                 Parameters.MutableTestsParameters iParams =
1096                     (Parameters.MutableTestsParameters) (p.getTestsParameters());
1097                 iParams.setTestsMode(Parameters.MutableTestsParameters.SPECIFIED_TESTS);
1098                 iParams.setSpecifiedTests(tests);
1099             }
1100         else
1101             throw new Fault(i18n, "cnfg.tests.notEditable");
1102         }
1103 
1104         private String[] tests;
1105     }
1106 
1107     //--------------------------------------------------------------------------
1108 
1109     private static class TestSuiteCommand extends Command
1110     {
1111         static String[] getNames() {
1112             return new String[] { "testsuite", "ts" };
1113         }
1114 
1115         TestSuiteCommand(ListIterator<String> argIter) throws Fault {
1116             super(getNames()[0]);
1117 
1118             while (argIter.hasNext()) {
1119                 String arg = nextArg(argIter);
1120                 if (arg.equalsIgnoreCase("-preferred"))
1121                     preferFlag = true;
1122                 else if (arg.startsWith("-"))
1123                     throw new Fault(i18n, "cnfg.ts.badArg", arg);
1124                 else {
1125                     path = new File(arg);
1126                     return;
1127                 }
1128             }   // while
1129 
1130             // if we are here, args are exhausted or invalid
1131             throw new Fault(i18n, "cnfg.ts.missingArg");
1132         }
1133 
1134         TestSuiteCommand(File path) {
1135             super(path.getPath());
1136             this.path = path;
1137         }
1138 
1139         public URL getCustomSplash() {
1140             String basePath = path.getAbsolutePath() +
1141                               File.separator + "lib";
1142             DirectoryClassLoader loader =
1143                     new DirectoryClassLoader(basePath);
1144             try {
1145                 ResourceBundle b = ResourceBundle.getBundle("splash",
1146                                         Locale.getDefault(), loader);
1147                 String icon = b.getString("splash.icon");
1148                 // could support a classpath value in the bundle
1149                 // and use PathClassLoader to generate the icon
1150                 File f = new File(icon);
1151                 if (!f.isAbsolute()) {
1152                     f = new File(basePath, icon);
1153                 }
1154                 if (f.canRead())
1155                     try {
1156                         return f.toURL();
1157                     }
1158                     catch (java.net.MalformedURLException e) {
1159                         return null;
1160                     }
1161                 else
1162                     return null;
1163             }
1164             // catch all possible exceptions from ResourceBundle
1165             catch (MissingResourceException m) {
1166                 return null;
1167             }
1168             catch (NullPointerException e) {
1169                 return null;
1170             }
1171             catch (ClassCastException e) {
1172                 return null;
1173             }
1174         }
1175 
1176         /**
1177          * Get custom help set for harness help.
1178          * A file help.properties must be in the <code>lib</code> directory of
1179          * the test suite.  An internationalization-aware search is then done
1180          * to find a properties bundle named "help".  That bundle must contain
1181          * a classpath entry, which is then used to generate the return value.
1182          * The classpath value is relative to the root of the test suite, not
1183          * the <code>lib</code> directory.
1184          */
1185         ClassLoader getCustomHelpLoader() {
1186             try {
1187                 String basePath = path.getCanonicalPath() +
1188                                   File.separator + "lib";
1189                 DirectoryClassLoader loader =
1190                         new DirectoryClassLoader(basePath);
1191 
1192                 ResourceBundle b = ResourceBundle.getBundle("help",
1193                                         Locale.getDefault(), loader);
1194                 String cp = b.getString("classpath");
1195 
1196                 // NOTES: PathClassLoader does not currently support resources
1197                 //        DirectionClassLoader cannot load from jar files
1198                 //PathClassLoader cl = new PathClassLoader(path, cp);
1199                 //DirectoryClassLoader cl = new DirectoryClassLoader(
1200                 //        path.getPath() + File.separator + cp);
1201                 File f = new File(cp);
1202                 if (!f.isAbsolute()) {
1203                     f = new File(path.getPath(), cp);
1204                 }
1205                 URLClassLoader cl = new URLClassLoader(new URL[] {f.toURL()},
1206                                             this.getClass().getClassLoader());
1207 
1208                 return cl;
1209             }
1210             // catch all possible exceptions from ResourceBundle
1211             catch (MissingResourceException m) {
1212                 return null;
1213             }
1214             catch (NullPointerException e) {
1215                 return null;
1216             }
1217             catch (ClassCastException e) {
1218                 return null;
1219             }
1220             catch (IOException e) {
1221                 return null;
1222             }
1223         }
1224 
1225         public void run(CommandContext ctx) throws Fault {
1226             /*OLD
1227             if (ctx.getTestSuite() != null)
1228                 throw new Fault(i18n, "cnfg.testSuiteAlreadySet");
1229 
1230             try {
1231                 ctx.setTestSuite(TestSuite.open(path));
1232             }
1233             catch (FileNotFoundException e) {
1234                 throw new Fault(i18n, "cnfg.ts.cantFindTestSuite", path);
1235             }
1236             catch (TestSuite.Fault e) {
1237                 throw new Fault(i18n, "cnfg.ts.cantOpenTestSuite", e.getMessage());
1238             }
1239             */
1240             if (!path.exists())
1241                 throw new Fault(i18n, "cnfg.ts.cantFindTestSuite", path);
1242 
1243             if (!TestSuite.isTestSuite(path))
1244                 throw new Fault(i18n, "cnfg.ts.notATestSuite", path);
1245 
1246             try {
1247                 ctx.setTestSuite(path);
1248 
1249                 if (preferFlag) {
1250                     // searching desktop history to find previous compatible workdir
1251                     // if none, continue as normal
1252                     // this is not the best logical place to do this, but there doesn't
1253                     // seem to be another good place in the current architecture.
1254                     // although perhaps it would be good to defer this processing to a
1255                     // little later in the command processing?
1256                     Map<String, String> p = Desktop.getPreviousDesktop(null);
1257                     String s = p.get("tool.count");
1258                     if (s != null) {
1259                         int count = Integer.parseInt(s);
1260                         for (int i = 0; i < count; i++) {
1261                             s = p.get("tool." + i + ".class");
1262                             if ("com.sun.javatest.exec.ExecTool".equals(s)) {
1263                                 s = p.get("tool." + i + ".testSuite");
1264 
1265                                 // this tool instance does not have a test suite
1266                                 if (s == null)
1267                                     continue;
1268 
1269                                 String s1 = path.getPath();
1270                                 String s2 = s;
1271                                 try {
1272                                     s1 = path.getCanonicalPath();
1273                                 }
1274                                 catch (IOException e) {
1275                                     // ignore accept default value of s1
1276                                 }
1277 
1278                                 try {
1279                                     File file = new File(s2);
1280                                     s2 = file.getCanonicalPath();
1281                                 }
1282                                 catch (IOException e) {
1283                                     // ignore accept default value of s2
1284                                 }
1285 
1286                                 if (s1.equals(s2)) {
1287                                     s = p.get("tool." + i + ".workDir");
1288                                     if (s != null &&
1289                                         WorkDirectory.isUsableWorkDirectory(
1290                                             new File(s))) {
1291                                         // found workdir to use as preferred workdir
1292                                         ctx.setDefaultWorkDir(s);
1293 
1294                                         // we found WD,
1295                                         // try to restore filter now
1296 
1297                                         s = p.get("tool." + i + ".filter");
1298                                         Map<String, String> data = collectSpecificData("tool." + i + ".", p);
1299 
1300                                         if (s != null) {
1301                                             ctx.setDesktopData(data);
1302                                         }
1303 
1304                                         break;
1305                                     }
1306                                     else {
1307                                         if (s != null)
1308                                             System.out.println(i18n.getString("cnfg.badWorkdir", s));
1309                                         continue;
1310                                     }
1311                                 }
1312                             }
1313                         }   // for
1314                     }
1315                 }
1316             }
1317             catch (CommandContext.Fault e) {
1318                 throw new Fault(e);
1319             }
1320         }
1321 
1322         private File path;
1323         private boolean preferFlag;
1324 
1325         private Map<String, String> collectSpecificData(String prefix, Map<String, String> p) {
1326             Set<Entry<String, String>> s = p.entrySet();
1327             Iterator<Entry<String, String>> it = s.iterator();
1328             Map<String, String> res = new HashMap<>();
1329             while (it.hasNext()) {
1330                 Entry<String, String> en = it.next();
1331                 if (en.getKey().toString().startsWith(prefix)) {
1332                     String key = en.getKey();
1333                     key = key.substring(prefix.length());
1334                     if ("-workDir-config-class-mgr-".contains(key)) {
1335                     //if ("-class-mgr-".contains(key)) {
1336                         continue;
1337                     }
1338                     res.put(key, en.getValue());
1339                 }
1340             }
1341             return res;
1342         }
1343     }
1344 
1345     //--------------------------------------------------------------------------
1346 
1347     private static class TimeoutFactorCommand extends Command
1348     {
1349         static String getName() {
1350             return "timeoutfactor";
1351         }
1352 
1353         TimeoutFactorCommand(ListIterator<String> argIter) throws Fault {
1354             super(getName());
1355 
1356             if (!argIter.hasNext())
1357                 throw new Fault(i18n, "cnfg.tf.missingArg");
1358 
1359             String arg = nextArg(argIter);
1360 
1361             NumberFormat fmt = NumberFormat.getNumberInstance(); // will be locale-specific
1362             ParsePosition pos = new ParsePosition(0);
1363             Number num = fmt.parse(arg, pos);
1364             if (num != null && (pos.getIndex() == arg.length())) {
1365                 value = num.floatValue();
1366                 if (value < Parameters.TimeoutFactorParameters.MIN_TIMEOUT_FACTOR
1367                     || value > Parameters.TimeoutFactorParameters.MAX_TIMEOUT_FACTOR) {
1368                     throw new Fault(i18n, "cnfg.tf.badRange",
1369                                     new Object[] {
1370                                         arg,
1371                                         new Float(Parameters.TimeoutFactorParameters.MIN_TIMEOUT_FACTOR),
1372                                         new Float(Parameters.TimeoutFactorParameters.MAX_TIMEOUT_FACTOR) });
1373                 }
1374             }
1375             else
1376                 throw new Fault(i18n, "cnfg.tf.badValue", arg);
1377         }
1378 
1379         public void run(CommandContext ctx) throws Fault {
1380             InterviewParameters p = getConfig(ctx);
1381             if (p.getTimeoutFactorParameters() instanceof Parameters.MutableTimeoutFactorParameters) {
1382                 Parameters.MutableTimeoutFactorParameters cParams =
1383                 (Parameters.MutableTimeoutFactorParameters) (p.getTimeoutFactorParameters());
1384                 cParams.setTimeoutFactor(value);
1385             }
1386             else
1387                 throw new Fault(i18n, "cnfg.tf.notEditable");
1388         }
1389 
1390         private float value;
1391     }
1392 
1393     //--------------------------------------------------------------------------
1394 
1395     private static class WorkDirectoryCommand extends Command
1396     {
1397         static String[] getNames() {
1398             return new String[] { "workdirectory", "workdir", "wd" };
1399         }
1400 
1401         WorkDirectoryCommand(ListIterator<String> argIter) throws Fault {
1402             super(getNames()[0]);
1403 
1404             while (argIter.hasNext()) {
1405                 String arg = nextArg(argIter);
1406                 if (arg.equalsIgnoreCase("-create"))
1407                     createFlag = true;
1408                 else if (arg.equalsIgnoreCase("-overwrite")) {
1409                     createFlag = true;
1410                     overwriteFlag = true;
1411                 }
1412                 else if (arg.startsWith("-"))
1413                     throw new Fault(i18n, "cnfg.wd.badArg", arg);
1414                 else {
1415                     path = new File(arg);
1416                     return;
1417                 }
1418             }
1419 
1420             // drop through if path not given
1421             throw new Fault(i18n, "cnfg.wd.missingArg");
1422         }
1423 
1424         WorkDirectoryCommand(File path) {
1425             super(path.getPath());
1426             this.path = path;
1427         }
1428 
1429         public void run(CommandContext ctx) throws Fault {
1430             /*OLD
1431             TestSuite ts = ctx.getTestSuite();
1432             WorkDirectory wd = ctx.getWorkDirectory();
1433 
1434             if (wd != null)
1435                 throw new Fault(i18n, "cnfg.workDirAlreadySet");
1436 
1437             if (createFlag)
1438                 wd = createWorkDirectory(ts);
1439             else
1440                 wd = openWorkDirectory(ts);
1441 
1442             try {
1443                 ctx.setWorkDirectory(wd);
1444             }
1445             catch (TestSuite.Fault e) {
1446                 throw new Fault(i18n, "cnfg.wd.cantOpenTestSuiteForWorkDir", e.getMessage());
1447             }
1448             */
1449             if (!createFlag) {
1450                 if (!path.exists())
1451                     throw new Fault(i18n, "cnfg.wd.cantFindWorkDir", path);
1452                 if (!WorkDirectory.isWorkDirectory(path)
1453                     && !WorkDirectory.isEmptyDirectory(path))
1454                     throw new Fault(i18n, "cnfg.wd.notAWorkDirectory", path);
1455             }
1456 
1457             if (overwriteFlag) {
1458                 remove(path);
1459                 if (path.exists())
1460                     throw new Fault(i18n, "cnfg.wd.cantRemoveWorkDir", path);
1461             }
1462 
1463             try {
1464                 ctx.setWorkDirectory(path, createFlag);
1465             }
1466             catch (CommandContext.Fault e) {
1467                 throw new Fault(e);
1468             }
1469 
1470         }
1471 
1472         /*OLD
1473         private WorkDirectory createWorkDirectory(TestSuite ts) throws Fault {
1474             if (ts == null)
1475                 throw new Fault(i18n, "cnfg.wd.cantCreateWorkDir_noTestSuite");
1476 
1477             if (overwriteFlag) {
1478                 remove(path);
1479                 if (path.exists())
1480                     throw new Fault(i18n, "cnfg.wd.cantRemoveWorkDir", path);
1481             }
1482 
1483             try {
1484                 return WorkDirectory.create(path, ts);
1485             }
1486             catch (WorkDirectory.Fault e) {
1487                 throw new Fault(i18n, "cnfg.wd.cantCreateWorkDir",
1488                                 new Object[] { path, e.getMessage() } );
1489             }
1490         }
1491         */
1492 
1493         /*OLD
1494         private WorkDirectory openWorkDirectory(TestSuite ts) throws Fault {
1495             try {
1496                 WorkDirectory wd;
1497                 if (path.exists()) {
1498                     if (WorkDirectory.isWorkDirectory(path)) {
1499                         if (ts == null) {
1500                             wd = WorkDirectory.open(path);
1501                             ts = wd.getTestSuite();
1502                         }
1503                         else
1504                             wd = WorkDirectory.open(path, ts);
1505                     }
1506                     else if (WorkDirectory.isEmptyDirectory(path)) {
1507                         if (ts == null)
1508                             throw new Fault(i18n, "cnfg.wd.cantCreateWorkDir_noTestSuite", path);
1509                         else
1510                             wd = WorkDirectory.create(path, ts);
1511                     }
1512                     else
1513                         throw new Fault(i18n, "cnfg.wd.notWorkDir", path);
1514                 }
1515                 else
1516                     throw new Fault(i18n, "cnfg.wd.cantFindWorkDir", path);
1517 
1518                 if (wd.getTestSuite().getID() != ts.getID())
1519                     throw new Fault(i18n, "cnfg.wd.incompatibleWorkDir", path);
1520 
1521                 return wd;
1522             }
1523             catch (FileNotFoundException e) {
1524                 throw new Fault(i18n, "cnfg.wd.cantFindWorkDir", path);
1525             }
1526             catch (WorkDirectory.Fault e) {
1527                 throw new Fault(i18n, "cnfg.wd.cantOpenWorkDir", e.getMessage());
1528             }
1529         }
1530         */
1531 
1532         private void remove(File path) {
1533             if (path.exists()) {
1534                 if (path.isDirectory()) {
1535                     File[] files = path.listFiles();
1536                     for (int i = 0; i < files.length; i++)
1537                         remove(files[i]);
1538                     // workaround for leftover .nfs* files
1539                     String[] undeletables = path.list();
1540                     if (undeletables != null && undeletables.length > 0) {
1541                         for (int i = 0; i < undeletables.length; i++) {
1542                             String name = undeletables[i];
1543                             if (name.startsWith(".nfs")) {
1544                                 File fOld = new File(path, name);
1545                                 File fNew = new File(path.getParentFile(), name);
1546                                 boolean ok = fOld.renameTo(fNew);
1547                                 // discard ok result
1548                             }
1549                         }
1550                     }
1551                 }
1552                 path.delete();
1553             }
1554         }
1555 
1556         private File path;
1557         private boolean createFlag;
1558         private boolean overwriteFlag;
1559     }
1560 }