/*
* $Id$
*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.javatest;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import com.sun.interview.ErrorQuestion;
import com.sun.interview.FinalQuestion;
import com.sun.interview.Interview;
import com.sun.interview.Question;
import com.sun.javatest.tool.CustomPropagationController;
import com.sun.javatest.tool.FileHistory;
import com.sun.javatest.util.BackupPolicy;
import com.sun.javatest.util.I18NResourceBundle;
import com.sun.javatest.util.Properties;
/**
* Configuration parameters provided via an interview.
*
* @since 3.0
*/
public abstract class InterviewParameters
extends Interview
implements Parameters
{
/**
* Indicates problems when accessing the work directory.
*/
public static class WorkDirFault extends Interview.Fault {
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
*/
public WorkDirFault(ResourceBundle i18n, String s) {
super(i18n, s);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameter to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public WorkDirFault(ResourceBundle i18n, String s, Object o) {
super(i18n, s, o);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameters to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public WorkDirFault(ResourceBundle i18n, String s, Object[] o) {
super(i18n, s, o);
}
}
/**
* Indicates problems when accessing the test suite.
*/
public static class TestSuiteFault extends Interview.Fault {
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
*/
public TestSuiteFault(ResourceBundle i18n, String s) {
super(i18n, s);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameter to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public TestSuiteFault(ResourceBundle i18n, String s, Object o) {
super(i18n, s, o);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameters to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public TestSuiteFault(ResourceBundle i18n, String s, Object[] o) {
super(i18n, s, o);
}
}
/**
* Indicates problems when accessing the configuration file.
*/
public static class JTIFault extends Interview.Fault {
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
*/
public JTIFault(ResourceBundle i18n, String s) {
super(i18n, s);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameter to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public JTIFault(ResourceBundle i18n, String s, Object o) {
super(i18n, s, o);
}
/**
* Create a fault with an internationalized message.
* @param i18n The bundle from which to get the string.
* @param s The key for getting the string to be displayed from the
* supplied bundle.
* @param o Parameters to use when resolving the string from the bundle.
* @see java.text.MessageFormat
*/
public JTIFault(ResourceBundle i18n, String s, Object[] o) {
super(i18n, s, o);
}
}
/**
* The template manager is used to change behavior of
* template saving, the default implementation is
* the context manager of corresponding test suite.
*/
public interface TemplateManager {
/**
* This method is invoked each time before saving template.
* The template will be saved only if this method returns true.
* @param file template file
* @return true if this operation is allowed, false otherwise
*/
public boolean canSaveTemplate(File file);
}
public void setPropagationController(CustomPropagationController pc) {
this.pc = pc;
}
public CustomPropagationController getPropagationController() {
return pc;
}
private TemplateManager templateManager = null;
/**
* Create an InterviewParameters object.
* @param tag The tag used to qualify questions in this interview
*/
protected InterviewParameters(String tag) {
super(tag);
}
/**
* Set the work directory to be used for this test run.
* @param workDir the work directory to be used for this test run.
* It must match the test suite to be used for this test run
*/
public abstract void setWorkDirectory(WorkDirectory workDir);
/**
* Set given template manager for this InterviewParameters.
* @param tm new template manager
*/
public void setTemplateManger(TemplateManager tm) {
this.templateManager = tm;
}
/**
* Return the template manager for this InterviewParameters.
*/
public TemplateManager getTemplateManger() {
return templateManager;
}
/**
* Initialize an InterviewParameters object.
* This method is called when the object is created
* from an entry in a .jtt file.
* By default, the method throws an exception if any arguments
* are given. It should be redefined by any test suites that wish
* to support this type of initialization.
* @param args test suite specific args with which to initialize
* this InterviewParameters object
* @throws Interview.Fault if any problems occurred while processing the arguments
*/
public void init(String[] args) throws Fault {
if (args != null && args.length > 0)
throw new Fault(i18n, "ip.unknownArgs");
}
/**
* Clean up an InterviewParameters object.
* This method should be invoked at the moment InterviewParameters object
* becomes useless by the code, that controls it's lifecycle. For example,
* at the end of the method which created it's local instance.
*
* Any following invocations on this object may result in unpredictable
* exceptions because of object inconsistence.
*/
public void dispose() {
kflFiles = null;
backupPolicy = null;
cachedExcludeListFilter = null;
cachedKeywordsFilter = null;
cachedRelevantTestFilter = null;
cachedRelevantTestFilterEnv = null;
cachedStatusFilter = null;
cachedTestFilters = null;
pc = null;
templateManager = null;
}
//----------------------------------------------------------------------------
/**
* Get the name for this configuration.
* By default and for backwards compatibility, this defaults to the
* name of the test environment, which means that the whole environment
* may need to be evaluated to get the required value. Subtypes may
* choose to override this method to provide a more efficient
* implementation.
*
*
Since the default implementation gets the name from the test
* environment, clients should not use this method to determine
* the name for the test environment, unless this method is redefined.
* The default implementation detects such a circular usage, and
* returns null in this case.
*
* @return the name for this configuration, or null if not known.
*/
public synchronized String getName() {
if (inGetName)
return null;
try {
inGetName = true;
EnvParameters eParams = getEnvParameters();
if (eParams != null) {
// getName to get the name for the environment
TestEnvironment e = eParams.getEnv();
if (e != null)
return e.getName();
}
return null;
}
finally {
inGetName = false;
}
}
private boolean inGetName;
/**
* Get a description for this configuration.
* By default and for backwards compatibility, this defaults to the
* description entry in the test environment, which means that the
* whole environment may need to be evaluated to get the required value.
* Subtypes may choose to override this method to provide a more efficient
* implementation.
* @return a description for this configuration, or null if not known
*/
public String getDescription() {
EnvParameters eParams = getEnvParameters();
if (eParams != null) {
TestEnvironment e = eParams.getEnv();
if (e != null)
return e.getDescription();
}
return null;
}
//----------------------------------------------------------------------------
/**
* Get the next question to the asked after the initial prolog
* of questions.
* The default value is the result of getEnvFirstQuestion.
* @return the next question to be asked after the initial prolog
* of questions.
* @see #setFirstQuestion
*/
protected Question getPrologSuccessorQuestion() {
return getEnvFirstQuestion();
}
//----------------------------------------------------------------------------
public TestEnvironment getEnv() {
EnvParameters eParams = getEnvParameters();
if (eParams == null)
throw new NullPointerException();
else
return eParams.getEnv();
}
/**
* Get the first question to be asked concerning the environment to be
* set up and used for each test to be run. If these questions are
* contained in an interview, this method can be simply implemented as:
* return callInterview(
envInterview, getEnvSuccessorQuestion);
* @return the first question to be asked concerning the environment to be
* set up and used for each test to be run.
* @see #getEnvSuccessorQuestion
*/
protected abstract Question getEnvFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the environment to be set up and used for each test to be run.
* The default value is the result of getTestsFirstQuestion.
* @return the next question to be asked after those concerning
* the environment to be set up and used for each test to be run.
* @see #getEnvFirstQuestion
*/
protected Question getEnvSuccessorQuestion() {
return getTestsFirstQuestion();
}
public String[] getTests() {
TestsParameters iParams = getTestsParameters();
return (iParams == null ? null : iParams.getTests());
}
/**
* Get the first question to be asked concerning the set of tests
* and folders of tests to be run.
* @return the first question to be asked concerning the set of tests
* and folders of tests to be run.
* @see #getTestsSuccessorQuestion
*/
protected abstract Question getTestsFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the tests and folders of tests to be run.
* The default value is the result of getExcludeListFirstQuestion.
* @return the next question to be asked after those concerning
* the tests and folders of tests to be run.
* @see #getTestsFirstQuestion
*/
protected Question getTestsSuccessorQuestion() {
return getExcludeListFirstQuestion();
}
public ExcludeList getExcludeList() {
ExcludeListParameters eParams = getExcludeListParameters();
return (eParams == null ? new ExcludeList() : eParams.getExcludeList());
}
/**
* Get the combined known failures list.
* Interviews expecting to use known failures lists should generally override
* this method and add support for users to change it.
* @since 4.4
* @see #setKnownFailureFiles(java.io.File[])
* @see com.sun.javatest.interview.BasicInterviewParameters
* @return Current known failures list - combined from the one or more
* file specified by the user.
*/
public KnownFailuresList getKnownFailuresList() {
try {
if (kflFiles != null) {
return new KnownFailuresList(getKnownFailureFiles());
}
else {
return null;
}
}
catch (IOException e){
return null;
}
catch (KnownFailuresList.Fault f) {
// report it?
return null;
}
}
/**
* Set the set of KFL files.
* @since 4.4
* @param files The known failures list files. The array should contain
* one or more elements.
*/
public void setKnownFailureFiles(File[] files) {
kflFiles = files;
}
/**
* Get the current set of known failures list files.
* The default implementation will return the value in the kflFiles
* field, which subclasses may set.
* @since 4.4
* @see #setKnownFailureFiles(java.io.File[])
* @return The list of known failure list files. Null if none.
*/
public File[] getKnownFailureFiles() {
return kflFiles;
}
/**
* Get the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @return the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @see #getExcludeListSuccessorQuestion
*/
protected abstract Question getExcludeListFirstQuestion();
/**
* Get the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run.
* @return the first question to be asked concerning the exclude list
* to be used to exclude tests from the test run
* @deprecated Use getExcludeListFirstQuestion().
* @see #getExcludeListFirstQuestion
*/
protected Question getExcludeTableFirstQuestion() {
return getExcludeListFirstQuestion();
}
/**
* Get the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* The default value is the result of getKeywordsFirstQuestion,
* @return the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* @see #getExcludeListFirstQuestion
*/
protected Question getExcludeListSuccessorQuestion() {
return getKeywordsFirstQuestion();
}
/**
* Get the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run.
* @return the next question to be asked after those concerning
* the exclude list to be used to exclude tests from the test run
* @deprecated Use getExcludeListFirstQuestion().
* @see #getExcludeListSuccessorQuestion
*/
protected Question getExcludeTableSuccessorQuestion() {
return getExcludeListSuccessorQuestion();
}
public Keywords getKeywords() {
KeywordsParameters kParams = getKeywordsParameters();
return (kParams == null ? null : kParams.getKeywords());
}
/**
* Get the first question to be asked concerning the keywords
* that may be used to select tests for the test run.
* @return the first question to be asked concerning the keywords
* that may be used to select tests for the test run.
* @see #getKeywordsSuccessorQuestion
*/
protected abstract Question getKeywordsFirstQuestion();
/**
* Get the next question to be asked after those concerning
* the keywords that may be used to select tests for the test run.
* The default value is the result of getPriorStatusQuestion.
* @return the next question to be asked after those concerning
* the keywords that may be used to select tests for the test run.
* @see #getKeywordsFirstQuestion
*/
protected Question getKeywordsSuccessorQuestion() {
return getPriorStatusFirstQuestion();
}
public boolean[] getPriorStatusValues() {
PriorStatusParameters sParams = getPriorStatusParameters();
return (sParams == null ? null : sParams.getPriorStatusValues());
}
/**
* Get the first question to be asked concerning whether tests should
* be selected for execution according to their prior execution status.
* @return the first question to be asked concerning whether tests should
* be selected for execution according to their prior execution status.
* @see #getPriorStatusSuccessorQuestion
*/
protected abstract Question getPriorStatusFirstQuestion();
/**
* Get the next question to be asked after those concerning
* whether tests should be selected for execution according to their
* prior execution status.
* The default value is the result of getConcurrencyFirstQuestion
* @return the next question to be asked after those concerning
* whether tests should be selected for execution according to their
* prior execution status.
* @see #getPriorStatusFirstQuestion
*/
protected Question getPriorStatusSuccessorQuestion() {
return getConcurrencyFirstQuestion();
}
public int getConcurrency() {
ConcurrencyParameters cParams = getConcurrencyParameters();
return (cParams == null ? 1 : cParams.getConcurrency());
}
/**
* Get the first question concerning the number of tests that
* may be run in parallel.
* @return the first question concerning the number of tests that
* may be run in parallel.
* @see #getConcurrencySuccessorQuestion
*/
protected abstract Question getConcurrencyFirstQuestion();
/**
* Get the next question after those concerning the number
* of tests that may be run in parallel.
* The default is the result of getTimeoutFactorFirstQuestion
* @return the next question after those concerning the number
* of tests that may be run in parallel.
* @see #getConcurrencyFirstQuestion
*/
protected Question getConcurrencySuccessorQuestion() {
return getTimeoutFactorFirstQuestion();
}
public float getTimeoutFactor() {
TimeoutFactorParameters tParams = getTimeoutFactorParameters();
return (tParams == null ? 1 : tParams.getTimeoutFactor());
}
/**
* Get the first question concerning the scale factor to
* be applied to the standard timeout for each test.
* @return the first question concerning the scale factor to
* be applied to the standard timeout for each test.
* @see #getTimeoutFactorSuccessorQuestion
*/
protected abstract Question getTimeoutFactorFirstQuestion();
/**
* Get the next question after those concerning the scale factor to
* be applied to the standard timeout for each test.
* The default is the result of getEpilogFirstQuestion
* @return the next question after those concerning the scale factor to
* be applied to the standard timeout for each test.
* @see #getTimeoutFactorFirstQuestion
*/
protected Question getTimeoutFactorSuccessorQuestion() {
return getEpilogFirstQuestion();
}
/**
* Get the first question of the epilog, which should be asked after
* all the other questions in the configuration interview have been asked.
* The epilog should terminate in the standard way with a FinalQuestion.
* @return the first question of the epilog, which should be asked after
* all the other questions in the configuration interview have been asked.
*/
protected abstract Question getEpilogFirstQuestion();
//----------------------------------------------------------------------------
/**
* Determine whether all the configuration values are valid, by
* checking if the interview has been completed.
* If so, the result will be true; if not, the result will be false,
* and getErrorMessage will provide details about at least one of the
* invalid values.
* @return true if and only if all the configuration values are valid
* @see #getErrorMessage
* @see #isFinishable
*/
public boolean isValid() {
return isFinishable();
}
/**
* If there is an error in any of the configuration values,
* as indicated by isValid, this method will provide a detail
* message about the first question for which there is a problem.
* @return a detail message about the first question with an invalid answer,
* or null if none.
* @see #isValid
*/
public String getErrorMessage() {
Question[] path = getPath();
Question lastQuestion = path[path.length - 1];
if (lastQuestion instanceof FinalQuestion)
return null;
else if (lastQuestion instanceof ErrorQuestion)
return lastQuestion.getText();
else {
String v = lastQuestion.getStringValue();
return i18n.getString("ip.noAnswer",
new Object[] { lastQuestion.getSummary(),
lastQuestion.getText(),
lastQuestion.getTag(),
new Integer(v == null ? 0 : 1),
trim(v),
} );
}
}
private String trim(String text) {
return (text == null ? null
: text.length() < 40 ? text
: text.substring(0, 37) + "...");
}
//----------------------------------------------------------------------------
/**
* Get a filter which will filter tests according to the result
* of getExcludeList(). If the result of getExcludeList is null
* or an empty exclude list, the result of this method will also be null.
* @return a filter which will filter tests according to the result
* of getExcludeList()
* @deprecated Use getExcludeListFilter().
* @see #getExcludeListFilter
*/
public TestFilter getExcludeTableFilter() {
return getExcludeListFilter();
}
public TestFilter getExcludeListFilter() {
ExcludeList t = getExcludeList();
if (t == null)
cachedExcludeListFilter = null;
else if (cachedExcludeListFilter == null
|| cachedExcludeListFilter.getExcludeList() != t)
cachedExcludeListFilter = new ExcludeListFilter(t);
return cachedExcludeListFilter;
}
private ExcludeListFilter cachedExcludeListFilter;
public TestFilter getKeywordsFilter() {
Keywords k = getKeywords();
if (k == null)
cachedKeywordsFilter = null;
else if (cachedKeywordsFilter == null
|| cachedKeywordsFilter.getKeywords() != k)
cachedKeywordsFilter = new KeywordsFilter(k);
return cachedKeywordsFilter;
}
private KeywordsFilter cachedKeywordsFilter;
public TestFilter getPriorStatusFilter() {
WorkDirectory wd = getWorkDirectory();
TestResultTable r = (wd == null ? null : wd.getTestResultTable());
boolean[] s = getPriorStatusValues();
if (r == null || s == null)
cachedStatusFilter = null;
else if (cachedStatusFilter == null
|| cachedStatusFilter.getTestResultTable() != r
|| !equal(cachedStatusFilter.getStatusValues(), s))
cachedStatusFilter = new StatusFilter(s, r);
// else
// cachedStatusFilter is OK
return cachedStatusFilter;
}
private StatusFilter cachedStatusFilter;
public TestFilter getRelevantTestFilter() {
TestSuite ts = getTestSuite();
TestEnvironment env = getEnv();
if (ts == null || env == null)
cachedRelevantTestFilter = null;
else if (cachedRelevantTestFilter == null ||
ts != cachedRelevantTestFilterTestSuite ||
env != cachedRelevantTestFilterEnv) {
cachedRelevantTestFilter = ts.createTestFilter(env);
}
return cachedRelevantTestFilter;
}
private TestFilter cachedRelevantTestFilter;
private TestSuite cachedRelevantTestFilterTestSuite; // do we need this?
private TestEnvironment cachedRelevantTestFilterEnv;
public synchronized TestFilter[] getFilters() {
Vector v = new Vector<>();
TestFilter excludeFilter = getExcludeListFilter();
if (excludeFilter != null) {
v.addElement(excludeFilter);
}
TestFilter keywordFilter = getKeywordsFilter();
if (keywordFilter != null) {
v.addElement(keywordFilter);
}
TestFilter statusFilter = getPriorStatusFilter();
if (statusFilter != null) {
v.addElement(statusFilter);
}
TestFilter testSuiteFilter = null;
try {
testSuiteFilter = getRelevantTestFilter();
}
catch (Exception e) {
testSuiteFilter = null;
}
if (testSuiteFilter != null) {
v.addElement(testSuiteFilter);
}
if (v.size() == 0) {
return null;
}
else if (equal(v, cachedTestFilters)) {
return cachedTestFilters;
}
else {
TestFilter[] filters = new TestFilter[v.size()];
v.copyInto(filters);
return filters;
}
}
private static boolean equal(boolean[] b1, boolean[] b2) {
if (b1 == null || b2 == null)
return (b1 == b2);
if (b1.length != b2.length)
return false;
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i])
return false;
}
return true;
}
private static boolean equal(Vector v, TestFilter[] f) {
if (f == null || v.size() != f.length)
return false;
for (int i = 0; i < v.size(); i++) {
if (!v.elementAt(i).equals(f[i]))
return false;
}
return true;
}
private TestFilter[] cachedTestFilters;
//----------------------------------------------------------------------------
/**
* Determine if the current instance is a template or not.
* @return true if the current instance is a template,
* and false otherwise
*/
public boolean isTemplate() {
return isTemplate;
}
/**
* Set if the current instance is a template or not.
* For internal use only, architects should not use this.
*/
public void setTemplate(boolean tm) {
isTemplate = tm;
updatePath();
}
protected boolean isAutoUpdatableKey(String key) {
return isAutoUpdatableKey(key, null);
}
protected boolean isAutoUpdatableKey(String key, String subkey) {
return false;
}
protected boolean isUpdatableKey(String key) {
return true;
}
/**
* Return String path to the template file for the current instance.
* If the current instance is a template (isTemplate() returns true),
* the path to itself will be returned.
* @return String path to the template file, or null if the instance is
* not template-based
*/
public String getTemplatePath() {
if (isTemplate()) {
File f = getFile();
if (f != null) {
return f.getPath();
}
}
return templatePath;
}
/**
* Set the location of a configuration's master template.
* Do not change this value if this instance is a template.
*/
public void setTemplatePath(String tu) {
templatePath = tu;
}
/**
* Get the file associated with this interview.
* @return the file associated with this interview.
* @see #setFile
* @see #load
* @see #save
*/
public File getFile() {
return currFile;
}
/**
* Set the file associated with this interview. This file will be used
* by subsequent load and save operations.
* @param f The file to be associated with this interview.
* @see #getFile
* @see #load
* @see #save
*/
public void setFile(File f) {
currFile = f;
currFileLoaded = false;
if (f != null) {
currFileLastModified = f.lastModified();
}
else {
// means: unknown; will likely a trigger a reload
currFileLastModified = 0;
}
}
/**
* Determine if the specified file is an interview file,
* as determined by whether its extension is .jti or not.
* @param f the file to be checked
* @return true if the specified file is an interview file,
* and false otherwise
*/
public static boolean isInterviewFile(File f) {
return (f.getName().endsWith(".jti"));
}
/**
* Create an InterviewParameters as determined by the contents of an
* interview file.
* @param file the file to be read
* @return an InterviewParameters as determined by the contents of an
* interview file.
* @throws IOException is there is a problem reading the file
* @throws Interview.Fault if there is a problem instantiating the
* interview
*/
public static InterviewParameters open(File file)
throws IOException, Fault
{
return open(file, (TestSuite) null, (WorkDirectory) null);
}
/**
* Create an InterviewParameters by populating the interview for a specified
* test suite with responses from a given file.
* @param file the file to be read
* @param testSuite the test suite for which to create the interview
* @return an InterviewParameters as determined by the test suite
* and the contents of an interview file
* @throws IOException is there is a problem reading the file
* @throws Interview.Fault if there is a problem instantiating the
* interview
*/
public static InterviewParameters open(File file, TestSuite testSuite)
throws IOException, Fault
{
if (testSuite == null)
throw new NullPointerException();
return open(file, testSuite, null);
}
/**
* Create an InterviewParameters by populating the interview for a specified
* work directory with responses from a given file.
* @param file the file to be read
* @param workDir the work directory (implying the test suite) for which
* to create the interview
* @return an InterviewParameters as determined by the work directory
* and the contents of an interview file
* @throws IOException is there is a problem reading the file
* @throws Interview.Fault if there is a problem instantiating the
* interview
*/
public static InterviewParameters open(File file, WorkDirectory workDir)
throws IOException, Fault
{
if (workDir == null)
throw new NullPointerException();
return open(file, workDir.getTestSuite(), workDir);
}
/**
* @throws WorkDirFault If there is a problem finding the work directory.
* @throws TestSuiteFault If there is a problem finding the test suite.
* @throws JTIFault If there is a problem finding the JTI file. Not thrown
* if the file is corrupt or incompatible though.
* @throws Fault If there is any other problem opening the interview params, such as
* problems with data in the JTI, incompatibilities between the workdir,
* test suite or work dir.
*/
private static InterviewParameters open(File file, TestSuite testSuite, WorkDirectory workDir)
throws IOException, Fault
{
// note: the additional Fault types were introduced in JT 3.2.1
// read the .jti data
Map data;
try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
data = Properties.load(in);
}
catch (RuntimeException e) {
// can get IllegalArgumentException if the file is corrupt
throw new JTIFault(i18n, "ip.errorReadingFile", new Object[] { file, e });
}
// if the test suite has not been given, set it from the .jti data
if (testSuite == null) {
String s = data.get(TESTSUITE);
if (s == null)
throw new Fault(i18n, "ip.noTestSuiteInFile", file);
try {
testSuite = TestSuite.open(new File(s));
}
catch (FileNotFoundException e) {
throw new TestSuiteFault(i18n, "ip.cantFindTestSuiteInFile",
new Object[] { s, file });
}
catch (TestSuite.Fault e) {
throw new Fault(i18n, "ip.cantOpenTestSuiteInFile",
new Object[] { s, file, e.getMessage() } );
}
}
// if the work directory has not been given,
// set it from the .jti data if given
if (workDir == null) {
String s = data.get(WORKDIR);
if (s != null) {
try {
workDir = WorkDirectory.open(new File(s), testSuite);
}
catch (FileNotFoundException e) {
throw new WorkDirFault(i18n, "ip.cantFindWorkDirInFile",
new Object[] { s, file } );
}
catch (WorkDirectory.Fault e) {
throw new Fault(i18n, "ip.cantOpenWorkDirInFile",
new Object[] { s, file, e.getMessage() } );
}
}
}
InterviewParameters parameters;
// create the parameters object
try {
parameters = testSuite.createInterview();
}
catch (TestSuite.Fault e) {
throw new Fault(i18n, "ip.cantCreateInterviewForTestSuite",
new Object[] { testSuite.getPath(), e.getMessage() } );
}
// set the work dir in the parameters object
if (workDir != null)
parameters.setWorkDirectory(workDir);
// load the .jti data into the parameters object
try {
parameters.load(data, file);
}
catch (InterviewParameters.Fault e) {
throw new Fault(i18n, "ip.cantLoadInterview",
new Object[] { file, e.getMessage() });
}
return parameters;
}
public void clear() {
WorkDirectory wd = getWorkDirectory();
super.clear();
if (wd != null && TemplateUtilities.getTemplatePath(wd) != null) {
if (wd.getTestSuite() != null) {
try {
wd.getTestSuite().loadInterviewFromTemplate(
TemplateUtilities.getTemplateFile(wd), this);
} catch (TestSuite.Fault ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
setEdited(false);
currFile = null;
}
/**
* Open a a configuration file, based on paths for the configuration file,
* test suite and work directory. Any, but not all, of these paths may be null.
* Any non-null path must specify an appropriate existing file, otherwise
* an exception will be thrown.
* @param testSuitePath the path for the test suite; if not specified,
* the test suite will default from the work directory (if specified) or
* the configuration file.
* @param workDirPath the path for the work directory; if not specified,
* the work directory will the default from the config file (if specified),
* or will be null if no configuration file is given
* @param configFilePath the path for the configuration file; if not specified,
* the result will be a blank interview as created by the test suite.
* @return an InterviewParameters object created from the given arguments
* @throws Interview.Fault if there is any problem creating the
* result
*/
public static InterviewParameters open(String testSuitePath, String workDirPath, String configFilePath)
throws InterviewParameters.Fault
{
File ts = (testSuitePath != null && testSuitePath.length() > 0
? new File(testSuitePath) : null);
File wd = (workDirPath != null && workDirPath.length() > 0
? new File(workDirPath) : null);
File cf = (configFilePath != null && configFilePath.length() > 0
? new File(configFilePath) : null);
return open(ts, wd, cf);
}
/**
* Open a a configuration file, based on paths for the configuration file,
* test suite and work directory. Any, but not all, of these paths may be null.
* Any non-null path must specify an appropriate existing file, otherwise
* an exception will be thrown.
* @param testSuitePath the path for the test suite; if not specified,
* the test suite will default from the work directory (if specified) or
* the configuration file.
* @param workDirPath the path for the work directory; if not specified,
* the work directory will bdefault from the config file (if specified),
* or will be null if no configuration file is given
* @param configFilePath the path for the configuration file; if not specified,
* the result will be a blank interview as created by the test suite.
* @return an InterviewParameters object created from the gievn arguments
* @throws Interview.Fault if there is any problem creating the
* result
*/
public static InterviewParameters open(File testSuitePath, File workDirPath, File configFilePath)
throws InterviewParameters.Fault
{
// open test suite if specified
TestSuite testSuite;
if (testSuitePath != null) {
try {
testSuite = TestSuite.open(testSuitePath);
}
catch (FileNotFoundException e) {
throw new Fault(i18n, "ip.cantFindTestSuite", testSuitePath);
}
catch (IOException e) {
throw new Fault(i18n, "ip.cantOpenTestSuite", new Object[] { testSuitePath, e });
}
catch (TestSuite.Fault e) {
throw new Fault(i18n, "ip.cantOpenTestSuite", new Object[] { testSuitePath, e.getMessage() });
}
}
else
testSuite = null;
// open work directory if specified, defaulting test suite if appropriate
WorkDirectory workDir;
if (workDirPath != null) {
try {
if (testSuite == null) {
workDir = WorkDirectory.open(workDirPath);
testSuite = workDir.getTestSuite();
}
else
workDir = WorkDirectory.open(workDirPath, testSuite);
}
catch (FileNotFoundException e) {
throw new Fault(i18n, "ip.cantFindWorkDir", workDirPath);
}
catch (IOException e) {
throw new Fault(i18n, "ip.cantOpenWorkDir", new Object[] { workDirPath, e });
}
catch (WorkDirectory.Fault e) {
throw new Fault(i18n, "ip.cantOpenWorkDir", new Object[] { workDirPath, e.getMessage() });
}
}
else
workDir = null;
// open config file if specified, defaulting work dir and test suite if appropriate
// default config from test suite if appropriate
InterviewParameters config;
if (configFilePath == null) {
if (testSuite != null) {
try {
config = testSuite.createInterview();
}
catch (TestSuite.Fault e) {
throw new Fault(i18n, "ip.cantCreateInterviewForTestSuite", new Object[] { testSuitePath, e });
}
if (workDir != null) {
config.setWorkDirectory(workDir);
FileHistory h = FileHistory.getFileHistory(workDir, "configHistory.jtl");
File latestConfigFile = h.getLatestEntry();
if (latestConfigFile != null) {
try {
config.load(latestConfigFile);
}
catch (IOException e) {
// ignore?
} // catch
}
} // workdir != null
}
else
throw new Fault(i18n, "ip.noPaths");
}
else {
try {
if (workDir == null) {
if (testSuite == null) {
config = open(configFilePath);
testSuite = config.getTestSuite();
}
else
config = open(configFilePath, testSuite);
workDir = config.getWorkDirectory();
}
else
config = open(configFilePath, workDir);
}
catch (FileNotFoundException e) {
throw new Fault(i18n, "ip.cantFindConfigFile", configFilePath);
}
catch (IOException e) {
throw new Fault(i18n, "ip.cantOpenConfigFile", new Object[] { configFilePath, e });
}
}
// if still here, and had sufficient args, config should be open
// and fully initialized
return config;
}
/**
* Load the interview with the contents of the file associated with
* the interview. If the file does not exist, the interview will be
* cleared.
* @throws IOException is there is a problem reading the file
* @throws Interview.Fault if there is a problem loading the
* interview
* @return true if there was an update from template
*/
public boolean load() throws IOException, Fault {
File f = getFile();
if (f != null && f.exists())
return load(f);
else {
clear();
setEdited(false);
return false;
}
}
/**
* Load the interview with the contents of a specified file,
* which will become the default file associated with the interview.
* @param file the file to be loaded
* @throws FileNotFoundException if the specified file does not exist.
* @throws IOException is there is a problem reading the file
* @throws Interview.Fault if there is a problem loading the
* interview
* @return true if there was an update from template
*/
public boolean load(File file) throws FileNotFoundException, IOException, Fault {
try (InputStream in = new BufferedInputStream(new FileInputStream(file))) {
Map data = Properties.load(in);
return load(data, file);
}
}
/**
* Load the interview with data that has already been read from a specified file,
* which will become the default file associated with the interview.
* @param data the data to be loaded
* @param file the file from which the data was read
* @throws Interview.Fault if there is a problem loading the interview
* @return true if there was an update from template
*/
public boolean load(Map data, File file) throws Fault {
load(data);
// restore template state
String tm = data.get(IS_TEMPLATE);
setTemplate(tm != null && tm.equalsIgnoreCase(TRUE));
setEdited(false);
currFile = file;
currFileLastModified = file.lastModified();
currFileLoaded = true;
return checkForUpdates();
}
/**
* Returns true if there was update
*/
public boolean checkForUpdates() {
InterviewPropagator prop = new InterviewPropagator(this,
ignorableProps, ignorablePrefs);
return prop.checkForUpdate();
}
public void load(Map data, boolean checkChecksum) throws Fault {
super.load(data, checkChecksum);
String me = data.get(MARKERS_ENABLED);
setMarkersEnabled(me != null && me.equalsIgnoreCase(TRUE));
String mf = data.get(MARKERS_FILTER);
setMarkersFilterEnabled(mf != null && mf.equalsIgnoreCase(TRUE));
String tm = data.get(IS_TEMPLATE);
setTemplate(tm != null && tm.equalsIgnoreCase(TRUE));
String tu = null;
//if (isTemplate()) {
tu = data.get(TEMPLATE_PATH);
//} else {
//tu = (String) data.get(TEMPLATE_PREF + TEMPLATE_PATH);
//}
setTemplatePath(tu);
}
/**
* Load the interview as best as possible with the data in another
* Parameters object. If any of the various sub-objects as returned by
* getXXXParameters are not recognized, they will be ignored.
* @param other The Parameters object to be copied.
*/
public void load(Parameters other) {
loadTestsParameters(other.getTestsParameters());
loadExcludeListParameters(other.getExcludeListParameters());
loadKeywordsParameters(other.getKeywordsParameters());
loadPriorStatusParameters(other.getPriorStatusParameters());
loadEnvParameters(other.getEnvParameters());
loadConcurrencyParameters(other.getConcurrencyParameters());
loadTimeoutFactorParameters(other.getTimeoutFactorParameters());
}
private void loadTestsParameters(TestsParameters other) {
TestsParameters tp = getTestsParameters();
if (!(tp instanceof MutableTestsParameters))
return;
MutableTestsParameters mtp = (MutableTestsParameters) tp;
if (other instanceof MutableTestsParameters) {
MutableTestsParameters mop = (MutableTestsParameters) other;
mtp.setTestsMode(mop.getTestsMode());
mtp.setSpecifiedTests(mop.getSpecifiedTests());
}
else {
String[] tests = other.getTests();
if (tests == null) {
mtp.setTestsMode(MutableTestsParameters.ALL_TESTS);
mtp.setSpecifiedTests(null);
}
else {
mtp.setTestsMode(MutableTestsParameters.SPECIFIED_TESTS);
mtp.setSpecifiedTests(tests);
}
}
}
private void loadExcludeListParameters(ExcludeListParameters other) {
ExcludeListParameters tp = getExcludeListParameters();
if (!(tp instanceof MutableExcludeListParameters))
return;
MutableExcludeListParameters mtp = (MutableExcludeListParameters) tp;
if (other instanceof MutableExcludeListParameters) {
MutableExcludeListParameters mop = (MutableExcludeListParameters) other;
mtp.setExcludeMode(mop.getExcludeMode());
mtp.setCustomExcludeFiles(mop.getCustomExcludeFiles());
mtp.setLatestExcludeAutoCheckEnabled(mop.isLatestExcludeAutoCheckEnabled());
mtp.setLatestExcludeAutoCheckMode(mop.getLatestExcludeAutoCheckMode());
mtp.setLatestExcludeAutoCheckInterval(mop.getLatestExcludeAutoCheckInterval());
}
else {
mtp.setExcludeMode(MutableExcludeListParameters.CUSTOM_EXCLUDE_LIST);
mtp.setCustomExcludeFiles(null);
mtp.setLatestExcludeAutoCheckEnabled(false);
mtp.setLatestExcludeAutoCheckMode(MutableExcludeListParameters.CHECK_EVERY_X_DAYS);
mtp.setLatestExcludeAutoCheckInterval(0);
}
}
private void loadKeywordsParameters(KeywordsParameters other) {
KeywordsParameters tp = getKeywordsParameters();
if (!(tp instanceof MutableKeywordsParameters))
return;
MutableKeywordsParameters mtp = (MutableKeywordsParameters) tp;
if (other instanceof MutableKeywordsParameters) {
MutableKeywordsParameters mop = (MutableKeywordsParameters) other;
mtp.setKeywordsMode(mop.getKeywordsMode());
mtp.setMatchKeywords(mop.getMatchKeywordsMode(), mop.getMatchKeywordsValue());
}
else {
Keywords k = other.getKeywords();
if (k == null) {
mtp.setKeywordsMode(MutableKeywordsParameters.NO_KEYWORDS);
mtp.setMatchKeywords(MutableKeywordsParameters.EXPR, "");
}
else {
mtp.setKeywordsMode(MutableKeywordsParameters.MATCH_KEYWORDS);
mtp.setMatchKeywords(MutableKeywordsParameters.EXPR, k.toString());
}
}
}
private void loadPriorStatusParameters(PriorStatusParameters other) {
PriorStatusParameters tp = getPriorStatusParameters();
if (!(tp instanceof MutablePriorStatusParameters))
return;
MutablePriorStatusParameters mtp = (MutablePriorStatusParameters) tp;
if (other instanceof MutablePriorStatusParameters) {
MutablePriorStatusParameters mop = (MutablePriorStatusParameters) other;
mtp.setPriorStatusMode(mop.getPriorStatusMode());
mtp.setMatchPriorStatusValues(mop.getMatchPriorStatusValues());
}
else {
boolean[] b = other.getPriorStatusValues();
if (b == null) {
mtp.setPriorStatusMode(MutablePriorStatusParameters.NO_PRIOR_STATUS);
mtp.setMatchPriorStatusValues(new boolean[Status.NUM_STATES]);
}
else {
mtp.setPriorStatusMode(MutablePriorStatusParameters.MATCH_PRIOR_STATUS);
mtp.setMatchPriorStatusValues(b);
}
}
}
private void loadEnvParameters(EnvParameters other) {
EnvParameters tp = getEnvParameters();
if (!(tp instanceof LegacyEnvParameters))
return;
LegacyEnvParameters ltp = (LegacyEnvParameters) tp;
if (other instanceof LegacyEnvParameters) {
LegacyEnvParameters lop = (LegacyEnvParameters) other;
ltp.setEnvFiles(lop.getEnvFiles());
ltp.setEnvName(lop.getEnvName());
}
}
private void loadConcurrencyParameters(ConcurrencyParameters other) {
ConcurrencyParameters tp = getConcurrencyParameters();
if (!(tp instanceof MutableConcurrencyParameters))
return;
MutableConcurrencyParameters mtp = (MutableConcurrencyParameters) tp;
mtp.setConcurrency(other.getConcurrency());
}
private void loadTimeoutFactorParameters(TimeoutFactorParameters other) {
TimeoutFactorParameters tp = getTimeoutFactorParameters();
if (!(tp instanceof MutableTimeoutFactorParameters))
return;
MutableTimeoutFactorParameters mtp = (MutableTimeoutFactorParameters) tp;
mtp.setTimeoutFactor(other.getTimeoutFactor());
}
/**
* Save the current set of answers for the interview in the standard
* file associated with the interview.
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
* @see #getFile
*/
public void save() throws IOException, Fault {
File f = getFile();
if (f == null)
throw new IllegalStateException();
save(f);
}
/**
* Save the current state of the interview in a specified file,
* and make that file the new file associated with the interview.
* @param file the file in which to save the state of the interview
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
* @see #getFile
*/
public void save(File file) throws IOException, Fault {
save(file, false);
}
/**
* Save the current state of the interview in a specified file,
* and make that file the new file associated with the interview.
* @param file the file in which to save the state of the interview
* @param isTemplate
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
* @see #getFile
*/
public void save(File file, boolean isTemplate) throws IOException, Fault {
saveAs(file, true, true, isTemplate);
setEdited(false);
currFile = file;
currFileLastModified = file.lastModified();
currFileLoaded = true;
}
/**
* Save the current state of the interview in a specified file,
* including the paths for the test suite and work directory.
* @param file the file in which to save the state of the interview
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
*/
public void saveAs(File file)
throws IOException, Fault
{
saveAs(file, true, true);
}
/**
* Save the current state of the interview in a specified file.
* If the test suite path is not saved, the file can only be used
* as a configuration template.
* @param file the file in which to save the state of the interview
* @param saveTestSuite if true, the test suite path will be saved
* in the file.
* @param saveWorkDir if true, the work directory path will be saved
* in the file.
* @param isTemplate True, the interview will be saved as template.
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
*/
public void saveAs(File file, boolean saveTestSuite, boolean saveWorkDir, boolean isTemplate)
throws IOException, Fault
{
SortedMap data = new TreeMap<>();
setTemplate(isTemplate); // dubious, why do we need to do this?
if (saveTestSuite) {
TestSuite ts = getTestSuite();
if (ts != null)
data.put(TESTSUITE, ts.getPath());
}
if (saveWorkDir) {
WorkDirectory wd = getWorkDirectory();
if (wd != null)
data.put(WORKDIR, wd.getPath());
}
save(data);
if (this.isTemplate == true ) {
TemplateManager tm = this.templateManager;
if (tm != null && !tm.canSaveTemplate(file)) {
throw new Interview.Fault(i18n, "ip.badTmplPath");
}
}
OutputStream out;
if (backupPolicy == null)
out = new BufferedOutputStream(new FileOutputStream(file));
else
out = backupPolicy.backupAndOpenStream(file);
try {
Properties.store(data, out, "JT Harness Configuration Interview");
}
finally {
out.close();
}
}
/**
* Save the current state of the interview in a specified file.
* If the test suite path is not saved, the file can only be used
* as a configuration template.
* @param file the file in which to save the state of the interview
* @param saveTestSuite if true, the test suite path will be saved
* in the file.
* @param saveWorkDir if true, the work directory path will be saved
* in the file.
* @throws IOException is there is a problem writing the file
* @throws Interview.Fault if there is a problem preparing the
* interview to be written
*/
public void saveAs(File file, boolean saveTestSuite, boolean saveWorkDir)
throws IOException, Fault
{
saveAs(file, saveTestSuite, saveWorkDir, false);
}
public void save(Map data) {
if (markersEnabled)
data.put(MARKERS_ENABLED, TRUE);
if (markersFilterEnabled)
data.put(MARKERS_FILTER, TRUE);
if (isTemplate()) {
data.put(IS_TEMPLATE, TRUE);
storeTemplateProperties(new HashMap());
}
else {
WorkDirectory wd = getWorkDirectory();
if (wd != null && TemplateUtilities.getTemplatePath(wd) != null)
data.put(TEMPLATE_PATH, TemplateUtilities.getTemplatePath(wd));
}
String name = getName();
if (name != null)
data.put(NAME, name);
String desc = getDescription();
if (desc != null)
data.put(DESC, desc);
super.save(data);
}
/**
* Get the backup policy to be used when saving configuration files.
* @return the backup policy object to be used when saving configuration files
* @see #setBackupPolicy
*/
public BackupPolicy getBackupPolicy() {
return backupPolicy;
}
/**
* Set the backup policy to be used when saving configuration files.
* @param backupPolicy the backup policy object to be used when saving configuration files
* @see #getBackupPolicy
*/
public void setBackupPolicy(BackupPolicy backupPolicy) {
this.backupPolicy = backupPolicy;
}
/**
* Check if the current file has been loaded into this interview,
* or if the interview has been saved in it.
* @return true if the file associated with the interview was set as a
* side effect of load or save, or false if the file was just set by
* setFile.
*/
public boolean isFileLoaded() {
return currFileLoaded;
}
/**
* Determine if the file associated with this interview has been modified
* on disk after the last call of load or save.
* @return true if the file on disk has been modified after it was last
* used by load or save.
* @see #load()
* @see #save()
*/
public boolean isFileNewer() {
File f = getFile();
return (f != null && f.exists() && ((currFileLastModified == 0)
|| (f.lastModified() > currFileLastModified)));
}
//----------------------------------------------------------------------------
/**
* Check whether or not markers should be enabled.
* @return whether or not markers should be enabled
* @see #setMarkersEnabled
*/
public boolean getMarkersEnabled() {
return markersEnabled;
}
/**
* Specify whether or not markers should be enabled.
* @param on whether or not markers should be enabled
* @see #getMarkersEnabled
*/
public void setMarkersEnabled(boolean on) {
if (on != markersEnabled) {
markersEnabled = on;
setEdited(true);
}
}
/**
* Check whether or not the history list should be filtered to
* just show questions which have been marked.
* @return whether or not the history list should be filtered to
* just show questions which have been marked
* @see #setMarkersFilterEnabled
*/
public boolean getMarkersFilterEnabled() {
return markersFilterEnabled;
}
/**
* Specify whether or not the history list should be filtered to
* just show questions which have been marked.
* @param on whether or not the history list should be filtered to
* just show questions which have been marked
* @see #getMarkersFilterEnabled
*/
public void setMarkersFilterEnabled(boolean on) {
if (on != markersFilterEnabled) {
markersFilterEnabled = on;
setEdited(true);
}
}
//----------------------------------------------------------------------------
private final String [] ignorableProps = new String [] {
INTERVIEW,
LOCALE, TESTSUITE, WORKDIR, MARKERS,
IS_TEMPLATE, TEMPLATE_PATH, QUESTION};
private final String [] ignorablePrefs = new String [] { MARKERS_PREF, EXTERNAL_PREF, TEMPLATE_PREF};
private BackupPolicy backupPolicy;
private boolean markersEnabled;
private boolean markersFilterEnabled;
private File currFile;
private boolean isTemplate;
private String templatePath;
private long currFileLastModified;
private boolean currFileLoaded;
protected File[] kflFiles;
private CustomPropagationController pc = new CustomPropagationController();
static final String TESTSUITE = "TESTSUITE";
static final String WORKDIR = "WORKDIR";
static final String NAME = "NAME";
static final String DESC = "DESCRIPTION";
static final String MARKERS_ENABLED = "MARKERS.enabled";
static final String MARKERS_FILTER = "MARKERS.filter";
static final String IS_TEMPLATE = "IS_TEMPLATE";
static final String TEMPLATE_PATH = "TEMPLATE_PATH";
static final String TRUE = "true";
private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(InterviewParameters.class);
}