2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
* RemoteExperiment.java
19
* Copyright (C) 2000 University of Waikato, Hamilton, New Zealand
24
package weka.experiment;
26
import weka.core.FastVector;
27
import weka.core.Option;
28
import weka.core.OptionHandler;
29
import weka.core.Queue;
30
import weka.core.SerializedObject;
31
import weka.core.Utils;
32
import weka.core.xml.KOML;
33
import weka.core.xml.XMLOptions;
34
import weka.experiment.xml.XMLExperiment;
36
import java.io.BufferedInputStream;
37
import java.io.BufferedOutputStream;
39
import java.io.FileInputStream;
40
import java.io.FileOutputStream;
41
import java.io.ObjectInputStream;
42
import java.io.ObjectOutputStream;
43
import java.rmi.Naming;
44
import java.util.Enumeration;
46
import javax.swing.DefaultListModel;
49
* Holds all the necessary configuration information for a distributed
50
* experiment. This object is able to be serialized for storage on disk.<p>
52
* This class is experimental at present. Has been tested using
53
* CSVResultListener (sending results to standard out) and
54
* DatabaseResultListener (InstantDB + RmiJdbc bridge). <p>
58
* Start InstantDB (with the RMI bridge) on some machine. If using java2
59
* then specify -Djava.security.policy=db.policy to the
60
* virtual machine. Where db.policy is as follows: <br>
63
* permission java.security.AllPermission;
67
* Start RemoteEngine servers on x machines as per the instructons in the
68
* README_Experiment_Gui file. There must be a
69
* DatabaseUtils.props in either the HOME or current directory of each
70
* machine, listing all necessary jdbc drivers.<p>
72
* The machine where a RemoteExperiment is started must also have a copy
73
* of DatabaseUtils.props listing the URL to the machine where the
74
* database server is running (RmiJdbc + InstantDB). <p>
76
* Here is an example of starting a RemoteExperiment: <p>
80
* java -Djava.rmi.server.codebase=file:/path to weka classes/ \
81
* weka.experiment.RemoteExperiment -L 1 -U 10 \
82
* -T /home/ml/datasets/UCI/iris.arff \
83
* -D "weka.experiment.DatabaseResultListener" \
84
* -P "weka.experiment.RandomSplitResultProducer" \
85
* -h rosebud.cs.waikato.ac.nz -h blackbird.cs.waikato.ac.nz -r -- \
86
* -W weka.experiment.ClassifierSplitEvaluator -- \
87
* -W weka.classifiers.bayes.NaiveBayes
90
* The "codebase" property tells rmi where to serve up weka classes from.
91
* This can either be a file url (as long as a shared file system is being
92
* used that is accessable by the remoteEngine servers), or http url (which
93
* of course supposes that a web server is running and you have put your
94
* weka classes somewhere that is web accessable). If using a file url the
95
* trailing "/" is *most* important unless the weka classes are in a jar
98
<!-- options-start -->
99
* Valid options are: <p/>
101
* <pre> -L <num>
102
* The lower run number to start the experiment from.
105
* <pre> -U <num>
106
* The upper run number to end the experiment at (inclusive).
109
* <pre> -T <arff file>
110
* The dataset to run the experiment on.
111
* (required, may be specified multiple times)</pre>
113
* <pre> -P <class name>
114
* The full class name of a ResultProducer (required).
115
* eg: weka.experiment.RandomSplitResultProducer</pre>
117
* <pre> -D <class name>
118
* The full class name of a ResultListener (required).
119
* eg: weka.experiment.CSVResultListener</pre>
121
* <pre> -N <string>
122
* A string containing any notes about the experiment.
123
* (default none)</pre>
126
* Options specific to result producer weka.experiment.RandomSplitResultProducer:
129
* <pre> -P <percent>
130
* The percentage of instances to use for training.
134
* Save raw split evaluator output.</pre>
136
* <pre> -O <file/directory name/path>
137
* The filename where raw output will be stored.
138
* If a directory name is specified then then individual
139
* outputs will be gzipped, otherwise all output will be
140
* zipped to the named file. Use in conjuction with -D. (default splitEvalutorOut.zip)</pre>
142
* <pre> -W <class name>
143
* The full class name of a SplitEvaluator.
144
* eg: weka.experiment.ClassifierSplitEvaluator</pre>
147
* Set when data is not to be randomized and the data sets' size.
148
* Is not to be determined via probabilistic rounding.</pre>
151
* Options specific to split evaluator weka.experiment.ClassifierSplitEvaluator:
154
* <pre> -W <class name>
155
* The full class name of the classifier.
156
* eg: weka.classifiers.bayes.NaiveBayes</pre>
158
* <pre> -C <index>
159
* The index of the class for which IR statistics
160
* are to be output. (default 1)</pre>
162
* <pre> -I <index>
163
* The index of an attribute to output in the
164
* results. This attribute should identify an
165
* instance in order to know which instances are
166
* in the test set of a cross validation. if 0
167
* no output (default 0).</pre>
170
* Add target and prediction columns to the result
171
* for each fold.</pre>
174
* Options specific to classifier weka.classifiers.rules.ZeroR:
178
* If set, classifier is run in debug mode and
179
* may output additional info to the console</pre>
183
* @author Mark Hall (mhall@cs.waikato.ac.nz)
184
* @version $Revision: 1.15 $
186
public class RemoteExperiment
189
/** for serialization */
190
static final long serialVersionUID = -7357668825635314937L;
192
/** The list of objects listening for remote experiment events */
193
private FastVector m_listeners = new FastVector();
195
/** Holds the names of machines with remoteEngine servers running */
196
protected DefaultListModel m_remoteHosts = new DefaultListModel();
198
/** The queue of available hosts */
199
private Queue m_remoteHostsQueue = new Queue();
201
/** The status of each of the remote hosts */
202
private int [] m_remoteHostsStatus;
204
/** The number of times tasks have failed on each remote host */
205
private int [] m_remoteHostFailureCounts;
207
/** status of the remote host: available */
208
protected static final int AVAILABLE=0;
209
/** status of the remote host: in use */
210
protected static final int IN_USE=1;
211
/** status of the remote host: connection failed */
212
protected static final int CONNECTION_FAILED=2;
213
/** status of the remote host: some other failure */
214
protected static final int SOME_OTHER_FAILURE=3;
216
// protected static final int TO_BE_RUN=0;
217
// protected static final int PROCESSING=1;
218
// protected static final int FAILED=2;
219
// protected static final int FINISHED=3;
221
/** allow at most 3 failures on a host before it is removed from the list
223
protected static final int MAX_FAILURES=3;
225
/** Set to true if MAX_FAILURES exceeded on all hosts or connections fail
226
on all hosts or user aborts experiment (via gui) */
227
private boolean m_experimentAborted = false;
229
/** The number of hosts removed due to exceeding max failures */
230
private int m_removedHosts;
232
/** The count of failed sub-experiments */
233
private int m_failedCount;
235
/** The count of successfully completed sub-experiments */
236
private int m_finishedCount;
238
/** The base experiment to split up into sub experiments for remote
240
private Experiment m_baseExperiment = null;
242
/** The sub experiments */
243
protected Experiment [] m_subExperiments;
245
/** The queue of sub experiments waiting to be processed */
246
private Queue m_subExpQueue = new Queue();
248
/** The status of each of the sub-experiments */
249
protected int [] m_subExpComplete;
252
* If true, then sub experiments are created on the basis of data sets
253
* rather than run number.
255
protected boolean m_splitByDataSet = true;
259
* Returns true if sub experiments are to be created on the basis of
262
* @return a <code>boolean</code> value indicating whether sub
263
* experiments are to be created on the basis of data set (true) or
264
* run number (false).
266
public boolean getSplitByDataSet() {
267
return m_splitByDataSet;
271
* Set whether sub experiments are to be created on the basis of
274
* @param sd true if sub experiments are to be created on the basis
275
* of data set. Otherwise sub experiments are created on the basis of
278
public void setSplitByDataSet(boolean sd) {
279
m_splitByDataSet = sd;
283
* Construct a new RemoteExperiment using an empty Experiment as base
285
* @throws Exception if the base experiment is null
287
public RemoteExperiment() throws Exception {
288
this(new Experiment());
292
* Construct a new RemoteExperiment using a base Experiment
293
* @param base the base experiment to use
294
* @throws Exception if the base experiment is null
296
public RemoteExperiment(Experiment base) throws Exception {
297
setBaseExperiment(base);
301
* Add an object to the list of those interested in recieving update
302
* information from the RemoteExperiment
303
* @param r a listener
305
public void addRemoteExperimentListener(RemoteExperimentListener r) {
306
m_listeners.addElement(r);
310
* Get the base experiment used by this remote experiment
311
* @return the base experiment
313
public Experiment getBaseExperiment() {
314
return m_baseExperiment;
318
* Set the base experiment. A sub experiment will be created for each
319
* run in the base experiment.
320
* @param base the base experiment to use.
321
* @throws Exception if supplied base experiment is null
323
public void setBaseExperiment(Experiment base) throws Exception {
325
throw new Exception("Base experiment is null!");
327
m_baseExperiment = base;
328
setRunLower(m_baseExperiment.getRunLower());
329
setRunUpper(m_baseExperiment.getRunUpper());
330
setResultListener(m_baseExperiment.getResultListener());
331
setResultProducer(m_baseExperiment.getResultProducer());
332
setDatasets(m_baseExperiment.getDatasets());
333
setUsePropertyIterator(m_baseExperiment.getUsePropertyIterator());
334
setPropertyPath(m_baseExperiment.getPropertyPath());
335
setPropertyArray(m_baseExperiment.getPropertyArray());
336
setNotes(m_baseExperiment.getNotes());
337
m_ClassFirst = m_baseExperiment.m_ClassFirst;
338
m_AdvanceDataSetFirst = m_baseExperiment.m_AdvanceDataSetFirst;
342
* Set the user notes.
344
* @param newNotes New user notes.
346
public void setNotes(String newNotes) {
348
super.setNotes(newNotes);
349
m_baseExperiment.setNotes(newNotes);
353
* Set the lower run number for the experiment.
355
* @param newRunLower the lower run number for the experiment.
357
public void setRunLower(int newRunLower) {
359
super.setRunLower(newRunLower);
360
m_baseExperiment.setRunLower(newRunLower);
364
* Set the upper run number for the experiment.
366
* @param newRunUpper the upper run number for the experiment.
368
public void setRunUpper(int newRunUpper) {
370
super.setRunUpper(newRunUpper);
371
m_baseExperiment.setRunUpper(newRunUpper);
375
* Sets the result listener where results will be sent.
377
* @param newResultListener the result listener where results will be sent.
379
public void setResultListener(ResultListener newResultListener) {
381
super.setResultListener(newResultListener);
382
m_baseExperiment.setResultListener(newResultListener);
386
* Set the result producer used for the current experiment.
388
* @param newResultProducer result producer to use for the current
391
public void setResultProducer(ResultProducer newResultProducer) {
393
super.setResultProducer(newResultProducer);
394
m_baseExperiment.setResultProducer(newResultProducer);
398
* Set the datasets to use in the experiment
399
* @param ds the list of datasets to use
401
public void setDatasets(DefaultListModel ds) {
402
super.setDatasets(ds);
403
m_baseExperiment.setDatasets(ds);
407
* Sets whether the custom property iterator should be used.
409
* @param newUsePropertyIterator true if so
411
public void setUsePropertyIterator(boolean newUsePropertyIterator) {
413
super.setUsePropertyIterator(newUsePropertyIterator);
414
m_baseExperiment.setUsePropertyIterator(newUsePropertyIterator);
418
* Sets the path of properties taken to get to the custom property
421
* @param newPropertyPath an array of PropertyNodes
423
public void setPropertyPath(PropertyNode [] newPropertyPath) {
425
super.setPropertyPath(newPropertyPath);
426
m_baseExperiment.setPropertyPath(newPropertyPath);
430
* Sets the array of values to set the custom property to.
432
* @param newPropArray a value of type Object which should be an
433
* array of the appropriate values.
435
public void setPropertyArray(Object newPropArray) {
436
super.setPropertyArray(newPropArray);
437
m_baseExperiment.setPropertyArray(newPropArray);
442
* Prepares a remote experiment for running, creates sub experiments
444
* @throws Exception if an error occurs
446
public void initialize() throws Exception {
447
if (m_baseExperiment == null) {
448
throw new Exception("No base experiment specified!");
451
m_experimentAborted = false;
454
m_RunNumber = getRunLower();
456
m_PropertyNumber = 0;
457
m_CurrentProperty = -1;
458
m_CurrentInstances = null;
461
if (m_remoteHosts.size() == 0) {
462
throw new Exception("No hosts specified!");
464
// initialize all remote hosts to available
465
m_remoteHostsStatus = new int [m_remoteHosts.size()];
466
m_remoteHostFailureCounts = new int [m_remoteHosts.size()];
468
m_remoteHostsQueue = new Queue();
469
// prime the hosts queue
470
for (int i=0;i<m_remoteHosts.size();i++) {
471
m_remoteHostsQueue.push(new Integer(i));
474
// set up sub experiments
475
m_subExpQueue = new Queue();
477
if (getSplitByDataSet()) {
478
numExps = m_baseExperiment.getDatasets().size();
480
numExps = getRunUpper() - getRunLower() + 1;
482
m_subExperiments = new Experiment[numExps];
483
m_subExpComplete = new int[numExps];
484
// create copy of base experiment
485
SerializedObject so = new SerializedObject(m_baseExperiment);
487
if (getSplitByDataSet()) {
488
for (int i = 0; i < m_baseExperiment.getDatasets().size(); i++) {
489
m_subExperiments[i] = (Experiment)so.getObject();
490
// one for each data set
491
DefaultListModel temp = new DefaultListModel();
492
temp.addElement(m_baseExperiment.getDatasets().elementAt(i));
493
m_subExperiments[i].setDatasets(temp);
494
m_subExpQueue.push(new Integer(i));
497
for (int i = getRunLower(); i <= getRunUpper(); i++) {
498
m_subExperiments[i-getRunLower()] = (Experiment)so.getObject();
499
// one run for each sub experiment
500
m_subExperiments[i-getRunLower()].setRunLower(i);
501
m_subExperiments[i-getRunLower()].setRunUpper(i);
503
m_subExpQueue.push(new Integer(i-getRunLower()));
509
* Inform all listeners of progress
510
* @param status true if this is a status type of message
511
* @param log true if this is a log type of message
512
* @param finished true if the remote experiment has finished
513
* @param message the message.
515
private synchronized void notifyListeners(boolean status,
519
if (m_listeners.size() > 0) {
520
for (int i=0;i<m_listeners.size();i++) {
521
RemoteExperimentListener r =
522
(RemoteExperimentListener)(m_listeners.elementAt(i));
523
r.remoteExperimentStatus(new RemoteExperimentEvent(status,
529
System.err.println(message);
536
public void abortExperiment() {
537
m_experimentAborted = true;
541
* Increment the number of successfully completed sub experiments
543
protected synchronized void incrementFinished() {
548
* Increment the overall number of failures and the number of failures for
550
* @param hostNum the index of the host to increment failure count
552
protected synchronized void incrementFailed(int hostNum) {
554
m_remoteHostFailureCounts[hostNum]++;
558
* Push an experiment back on the queue of waiting experiments
559
* @param expNum the index of the experiment to push onto the queue
561
protected synchronized void waitingExperiment(int expNum) {
562
m_subExpQueue.push(new Integer(expNum));
566
* Check to see if we have failed to connect to all hosts
568
* @return true if failed to connect to all hosts
570
private boolean checkForAllFailedHosts() {
571
boolean allbad = true;
572
for (int i = 0; i < m_remoteHostsStatus.length; i++) {
573
if (m_remoteHostsStatus[i] != CONNECTION_FAILED) {
580
notifyListeners(false,true,true,"Experiment aborted! All connections "
581
+"to remote hosts failed.");
587
* Returns some post experiment information.
588
* @return a String containing some post experiment info
590
private String postExperimentInfo() {
591
StringBuffer text = new StringBuffer();
592
text.append(m_finishedCount+(m_splitByDataSet
594
: " runs") + " completed successfully. "
595
+m_failedCount+" failures during running.\n");
596
System.err.print(text.toString());
597
return text.toString();
601
* Pushes a host back onto the queue of available hosts and attempts to
602
* launch a waiting experiment (if any).
603
* @param hostNum the index of the host to push back onto the queue of
606
protected synchronized void availableHost(int hostNum) {
608
if (m_remoteHostFailureCounts[hostNum] < MAX_FAILURES) {
609
m_remoteHostsQueue.push(new Integer(hostNum));
611
notifyListeners(false,true,false,"Max failures exceeded for host "
612
+((String)m_remoteHosts.elementAt(hostNum))
613
+". Removed from host list.");
618
// check for all sub exp complete or all hosts failed or failed count
620
if (m_failedCount == (MAX_FAILURES * m_remoteHosts.size())) {
622
notifyListeners(false,true,true,"Experiment aborted! Max failures "
623
+"exceeded on all remote hosts.");
627
if ((getSplitByDataSet() &&
628
(m_baseExperiment.getDatasets().size() == m_finishedCount)) ||
629
(!getSplitByDataSet() &&
630
((getRunUpper() - getRunLower() + 1) == m_finishedCount))) {
631
notifyListeners(false,true,false,"Experiment completed successfully.");
632
notifyListeners(false,true,true,postExperimentInfo());
636
if (checkForAllFailedHosts()) {
640
if (m_experimentAborted &&
641
(m_remoteHostsQueue.size() + m_removedHosts) == m_remoteHosts.size()) {
642
notifyListeners(false,true,true,"Experiment aborted. All remote tasks "
646
if (!m_subExpQueue.empty() && !m_experimentAborted) {
647
if (!m_remoteHostsQueue.empty()) {
648
int availHost, waitingExp;
650
availHost = ((Integer)m_remoteHostsQueue.pop()).intValue();
651
waitingExp = ((Integer)m_subExpQueue.pop()).intValue();
652
launchNext(waitingExp, availHost);
653
} catch (Exception ex) {
654
ex.printStackTrace();
661
* Launch a sub experiment on a remote host
662
* @param wexp the index of the sub experiment to launch
663
* @param ah the index of the available host to launch on
665
public void launchNext(final int wexp, final int ah) {
668
subExpThread = new Thread() {
670
m_remoteHostsStatus[ah] = IN_USE;
671
m_subExpComplete[wexp] = TaskStatusInfo.PROCESSING;
672
RemoteExperimentSubTask expSubTsk = new RemoteExperimentSubTask();
673
expSubTsk.setExperiment(m_subExperiments[wexp]);
674
String subTaskType = (getSplitByDataSet())
675
? "dataset :" + ((File)m_subExperiments[wexp].getDatasets().
676
elementAt(0)).getName()
677
: "run :" + m_subExperiments[wexp].getRunLower();
680
+((String)m_remoteHosts.elementAt(ah))
682
Compute comp = (Compute) Naming.lookup(name);
683
// assess the status of the sub-exp
684
notifyListeners(false,true,false,"Starting "
687
+((String)m_remoteHosts.elementAt(ah)));
688
Object subTaskId = comp.executeTask(expSubTsk);
689
boolean finished = false;
690
TaskStatusInfo is = null;
695
TaskStatusInfo cs = (TaskStatusInfo)comp.
696
checkStatus(subTaskId);
697
if (cs.getExecutionStatus() == TaskStatusInfo.FINISHED) {
698
// push host back onto queue and try launching any waiting
700
notifyListeners(false, true, false, cs.getStatusMessage());
701
m_remoteHostsStatus[ah] = AVAILABLE;
705
} else if (cs.getExecutionStatus() == TaskStatusInfo.FAILED) {
706
// a non connection related error---possibly host doesn't have
707
// access to data sets or security policy is not set up
708
// correctly or classifier(s) failed for some reason
709
notifyListeners(false, true, false, cs.getStatusMessage());
710
m_remoteHostsStatus[ah] = SOME_OTHER_FAILURE;
711
m_subExpComplete[wexp] = TaskStatusInfo.FAILED;
712
notifyListeners(false,true,false,subTaskType
713
+" "+cs.getStatusMessage()
714
+". Scheduling for execution on another host.");
716
// push experiment back onto queue
717
waitingExperiment(wexp);
718
// push host back onto queue and try launching any waiting
719
// sub-experiments. Host is pushed back on the queue as the
720
// failure may be temporary---eg. with InstantDB using the
721
// RMI bridge, two or more threads may try to create the
722
// experiment index or results table simultaneously; all but
723
// one will throw an exception. These hosts are still usable
730
notifyListeners(false, true, false, cs.getStatusMessage());
732
if (cs.getStatusMessage().
733
compareTo(is.getStatusMessage()) != 0) {
735
notifyListeners(false, true, false,
736
cs.getStatusMessage());
741
} catch (InterruptedException ie) {
745
} catch (Exception ce) {
746
m_remoteHostsStatus[ah] = CONNECTION_FAILED;
747
m_subExpComplete[wexp] = TaskStatusInfo.TO_BE_RUN;
748
System.err.println(ce);
749
ce.printStackTrace();
750
notifyListeners(false,true,false,"Connection to "
751
+((String)m_remoteHosts.elementAt(ah))
752
+" failed. Scheduling "
754
+" for execution on another host.");
755
checkForAllFailedHosts();
756
waitingExperiment(wexp);
758
if (isInterrupted()) {
759
System.err.println("Sub exp Interupted!");
764
subExpThread.setPriority(Thread.MIN_PRIORITY);
765
subExpThread.start();
769
* Overides the one in Experiment
770
* @throws Exception never throws an exception
772
public void nextIteration() throws Exception {
777
* overides the one in Experiment
779
public void advanceCounters() {
784
* overides the one in Experiment
786
public void postProcess() {
791
* Add a host name to the list of remote hosts
792
* @param hostname the host name to add to the list
794
public void addRemoteHost(String hostname) {
795
m_remoteHosts.addElement(hostname);
799
* Get the list of remote host names
800
* @return the list of remote host names
802
public DefaultListModel getRemoteHosts() {
803
return m_remoteHosts;
807
* Set the list of remote host names
808
* @param list the list of remote host names
810
public void setRemoteHosts(DefaultListModel list) {
811
m_remoteHosts = list;
815
* Overides toString in Experiment
816
* @return a description of this remote experiment
818
public String toString() {
819
String result = m_baseExperiment.toString();
821
result += "\nRemote Hosts:\n";
822
for (int i=0;i<m_remoteHosts.size();i++) {
823
result += ((String)m_remoteHosts.elementAt(i)) +'\n';
829
* Overides runExperiment in Experiment
831
public void runExperiment() {
832
int totalHosts = m_remoteHostsQueue.size();
833
// Try to launch sub experiments on all available hosts
834
for (int i = 0; i < totalHosts; i++) {
840
* Configures/Runs the Experiment from the command line.
842
* @param args command line arguments to the Experiment.
844
public static void main(String[] args) {
847
RemoteExperiment exp = null;
849
// get options from XML?
850
String xmlOption = Utils.getOption("xml", args);
851
if (!xmlOption.equals(""))
852
args = new XMLOptions(xmlOption).toArray();
854
Experiment base = null;
855
String expFile = Utils.getOption('l', args);
856
String saveFile = Utils.getOption('s', args);
857
boolean runExp = Utils.getFlag('r', args);
858
FastVector remoteHosts = new FastVector();
859
String runHost = " ";
860
while (runHost.length() != 0) {
861
runHost = Utils.getOption('h', args);
862
if (runHost.length() != 0) {
863
remoteHosts.addElement(runHost);
866
if (expFile.length() == 0) {
867
base = new Experiment();
869
base.setOptions(args);
870
Utils.checkForRemainingOptions(args);
871
} catch (Exception ex) {
872
ex.printStackTrace();
873
String result = "Usage:\n\n"
875
+ "\tLoad experiment from file (default use cli options)\n"
877
+ "\tSave experiment to file after setting other options\n"
878
+ "\t(default don't save)\n"
879
+ "-h <remote host name>\n"
880
+ "\tHost to run experiment on (may be specified more than once\n"
881
+ "\tfor multiple remote hosts)\n"
883
+ "\tRun experiment on (default don't run)\n"
884
+ "-xml <filename | xml-string>\n"
885
+ "\tget options from XML-Data instead from parameters\n"
887
Enumeration enm = ((OptionHandler)base).listOptions();
888
while (enm.hasMoreElements()) {
889
Option option = (Option) enm.nextElement();
890
result += option.synopsis() + "\n";
891
result += option.description() + "\n";
893
throw new Exception(result + "\n" + ex.getMessage());
899
if ( (KOML.isPresent()) && (expFile.toLowerCase().endsWith(KOML.FILE_EXTENSION)) ) {
900
tmp = KOML.read(expFile);
904
if (expFile.toLowerCase().endsWith(".xml")) {
905
XMLExperiment xml = new XMLExperiment();
906
tmp = xml.read(expFile);
910
FileInputStream fi = new FileInputStream(expFile);
911
ObjectInputStream oi = new ObjectInputStream(
912
new BufferedInputStream(fi));
913
tmp = oi.readObject();
916
if (tmp instanceof RemoteExperiment) {
917
exp = (RemoteExperiment)tmp;
919
base = (Experiment)tmp;
923
exp = new RemoteExperiment(base);
925
for (int i=0;i<remoteHosts.size();i++) {
926
exp.addRemoteHost((String)remoteHosts.elementAt(i));
928
System.err.println("Experiment:\n" + exp.toString());
930
if (saveFile.length() != 0) {
932
if ( (KOML.isPresent()) && (saveFile.toLowerCase().endsWith(KOML.FILE_EXTENSION)) ) {
933
KOML.write(saveFile, exp);
937
if (saveFile.toLowerCase().endsWith(".xml")) {
938
XMLExperiment xml = new XMLExperiment();
939
xml.write(saveFile, exp);
943
FileOutputStream fo = new FileOutputStream(saveFile);
944
ObjectOutputStream oo = new ObjectOutputStream(
945
new BufferedOutputStream(fo));
952
System.err.println("Initializing...");
954
System.err.println("Iterating...");
956
System.err.println("Postprocessing...");
959
} catch (Exception ex) {
960
ex.printStackTrace();
961
System.err.println(ex.getMessage());