package periman;
import java.awt.Font;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.ListModel;
import javax.swing.UIManager;
import org.apache.commons.cli.*;
@SuppressWarnings("serial")
public class Experimentor extends JFrame
{
private Configuration perimanConf;
private int currentShowingPage = 0;
private PageAndBox currentPage = null;
private JButton nextBtn;
private String perimanConfFileName;
// cache a custom form from the time it is loaded for the choose configuration
// to its first appearance.
private Map<String, Page> cachedCustomForms = new HashMap<String, Page>();
private Map<String, Class<?> > cachedCustomClasses = new HashMap<String, Class<?> >();
private String outputDirectory;
private UUID id;
private CommandLine cmd=null;
private final static char PERIMAN_CONF_ARGUMENT_OPTION = 'p';
private final static char OUTPUT_DIR_ARGUMENT_OPTION = 'o';
public String getID()
{
return id.toString();
}
public void setApplicationFont(Font font)
{
Enumeration<Object> enumer = UIManager.getDefaults().keys();
while(enumer.hasMoreElements())
{
Object key = enumer.nextElement();
Object value = UIManager.get(key);
if (value instanceof Font)
{
UIManager.put( key, new javax.swing.plaf.FontUIResource(font) );
}
}
}
public Experimentor(String[] args)
{
setApplicationFont( new Font( "Dialog", Font.PLAIN, 18 ) );
// get a universally unique id. this will identify the user and this
// experiment instance.
// result files will have this id to make them unique.
id = UUID.randomUUID();
setDefaultCloseOperation(EXIT_ON_CLOSE);
try {
parseProgramArguments(args);
} catch (ParseException e) {
JOptionPane.showMessageDialog(this, "***ERROR: " + e.getClass()
+ " " + e.getMessage() );
return;
}
// set the default output directory.
outputDirectory = System.getProperty("user.dir") + "/results/";
if(cmd.hasOption(PERIMAN_CONF_ARGUMENT_OPTION))
{
perimanConfFileName = cmd.getOptionValue(PERIMAN_CONF_ARGUMENT_OPTION);
}
if(cmd.hasOption(OUTPUT_DIR_ARGUMENT_OPTION))
{
outputDirectory = cmd.getOptionValue(OUTPUT_DIR_ARGUMENT_OPTION);
}
if( cmd.hasOption(PERIMAN_CONF_ARGUMENT_OPTION)== false )
{
boolean res = getPerimanConfigurationFileNameFromUser();
if(res == false)
return;
}
perimanConf = Configuration.load(perimanConfFileName);
setTitle("Experimentor");
createGui();
// iterate periman configuraton form list and run the
// configuration selector for any custom forms.
if(false == runConfigurationSelector())
return;
try{
showPage( currentShowingPage );
}
catch(Throwable e)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
JOptionPane.showMessageDialog( this, "Error, Could now show page number " + currentShowingPage + ".\n" + e.getClass() + ": " + e.getMessage() +"\n\nStack:\n" + sw.toString());
currentShowingPage++;
showPage( currentShowingPage );
return;
}
pack();
setVisible(true);
setExtendedState( MAXIMIZED_BOTH);
}
private void parseProgramArguments(String[] args) throws ParseException {
Option perimanConfOption = new Option("p" /*short name*/,
"periman_conf" /*long name*/,
true /*has arg*/ ,
"Periman Configuration file to use" /*description*/);
perimanConfOption.setArgs(1);
perimanConfOption.setArgName("Periman Configuration File");
Option outputOption = new Option("o", // short name
"output_dir", // long name
true, // has args
"The path to the output directory to hold the results." ); // description
outputOption.setArgs(1);
outputOption.setArgName("output directory");
Options options = new Options();
options.addOption( perimanConfOption );
options.addOption(outputOption);
CommandLineParser parser = new BasicParser();
cmd = parser.parse( options, args);
}
private boolean getPerimanConfigurationFileNameFromUser() {
PerimanConfChooser confChooser = new PerimanConfChooser(this, true);
confChooser.pack();
confChooser.setVisible(true);
if(confChooser.dialogAccept == false)
return false;
if(confChooser.getConfFileName() == null)
return false;
outputDirectory = confChooser.getOutDest();
perimanConfFileName = confChooser.getConfFileName();
return true;
}
private void createGui() {
setLayout( new BoxLayout( getContentPane(), BoxLayout.Y_AXIS) );
Box nextFormLayout = new Box( BoxLayout.X_AXIS);
nextFormLayout.add(Box.createHorizontalGlue());
nextBtn = new JButton("Next");
nextFormLayout.add(nextBtn);
nextFormLayout.add(Box.createHorizontalGlue());
add(nextFormLayout);
}
public void showNextPage()
{
try{
showPage( ++currentShowingPage );
}
catch(Throwable e)
{
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
currentShowingPage++;
JOptionPane.showMessageDialog( this, "Error, Could now show page number " + currentShowingPage + ".\n" + e.getClass() + ": " + e.getMessage() +"\n\nStack:\n" + sw.toString());
showPage( currentShowingPage );
}
}
// do clean up (if exist) and exit.
private void closeApp()
{
System.exit(0);
}
private void showPage(int pageNum)
{
ListModel lm = perimanConf.getForms();
if(lm.getSize() < (pageNum+1))
{
closeApp();
}
final String formName = lm.getElementAt(pageNum).toString();
if(currentPage != null)
{
remove(currentPage.getBox()); // remove the last page
nextBtn.removeActionListener( currentPage.getPage() ); // this fixes a bug that screener intercepted events not destined to it.
currentPage = null;
}
if(true == isHTMLForm(formName))
{
currentPage = new PageAndBox( (Page) showHTMLForm(formName) );
}
else
if(true == isQuestioneerForm(formName) )
{
currentPage = new PageAndBox( (Page) showQuestioneerForm(formName) );
}
else
if(true == isCustomForm( formName ) )
{
// a custom form is loaded when experimentor starts, to
// show the choose configuration dialog, it is then cached so
// it can be used later when it is time to show that custom form.
// after the custom form is shown for the first time it is deleted
// from cache so that other appearances of the form would use a new
// instance and not the cached
Page cached = cachedCustomForms.get(formName);
if(cached != null)
cachedCustomForms.remove( formName );
else
cached = (Page) loadClass( formName );
currentPage = new PageAndBox( cached );
}
if(null == currentPage)
{
JOptionPane.showMessageDialog( this, "Error, Could not detect type of form :" + formName);
return;
}
if(null == currentPage.getPage())
{
JOptionPane.showMessageDialog( this, "Error, Could load form :" + formName);
return;
}
currentPage.setExperimentor( this );
nextBtn.addActionListener( currentPage.getPage() );
currentPage.aboutToShowPage();
add( currentPage.getBox(), 0);
pack();
getContentPane().validate();
}
private Object showQuestioneerForm(String formName) {
return new QuestionnairePage(this, formName);
}
private boolean isQuestioneerForm(String formName) {
return doesFormDirHasFilesEndingWith(formName, "xml");
}
private Object showHTMLForm(String formName) {
return new HTMLPage(formName);
}
private boolean isHTMLForm(String formName) {
return doesFormDirHasFilesEndingWith(formName, "html");
}
private boolean isCustomForm(final String formName) {
return doesFormDirHasFilesEndingWith(formName, "class");
}
/** check whether the form folder has a file named with the same name of the form and with the
* appropriate extension for each type of form (postfix)*/
private boolean doesFormDirHasFilesEndingWith(final String formName, final String postfix)
{
final String fileNameThatIfExistMeansTypeFormFound = formName + "." + postfix;
final String formPath = System.getProperty("user.dir") + "/" + formName;
File f = new File( formPath );
File files[]=f.listFiles();
if(files==null)
return false;
for (int i = 0; i < files.length; i++)
{
final String currFileName = files[i].getName();
if( fileNameThatIfExistMeansTypeFormFound.equals(currFileName))
{
return true;
}
}
return false;
}
/**
* iterate the forms - run the configuration selector of every custom form.
* @return true if all configuration selector screens where loaded and shown w/o a hitch.
* */
private boolean runConfigurationSelector() {
ListModel lm = perimanConf.getForms();
for(int i=0 ; i < lm.getSize() ; ++i)
{
final String formName = lm.getElementAt(i).toString();
if(true == isCustomForm( formName ) )
{
// show configuration selector once for each form.
if(cachedCustomForms.containsKey( formName ) == true)
continue;
Page cf = (Page) loadClass(formName);
cf.setExperimentor(this);
boolean res;
try {
res = cf.configurationSelector();
} catch (Throwable e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
JOptionPane.showMessageDialog( this, "Error, Could now show "+
"\"Configuration Selector\" for form \"" +
formName +"\".\n" + e.getClass() + ": " + e.getMessage() +
"\n\nStack:\n" + sw.toString());
return false;
}
cachedCustomForms.put(formName, cf);
return res;
}
}
return true;
}
private Object loadClass(final String formName)
{
// if such form name already been loaded then pull it from cache
// and initiate it.
Class<?> cachedClass = cachedCustomClasses.get( formName );
if(cachedClass != null)
{
try {
return cachedClass.newInstance();
} catch (InstantiationException e) {
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
} catch (IllegalAccessException e) {
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
}
final String customFormClassPath =
System.getProperty("user.dir") + "/" + formName + "/";
File f = new File( customFormClassPath );
try{
ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
URL[] url={ f.toURI().toURL() };
URLClassLoader loader = new URLClassLoader(url, oldCl);
Class<?> c = loader.loadClass("periman."+formName );
cachedCustomClasses.put(formName, c);
return c.newInstance();
}
catch(ClassNotFoundException e)
{
JOptionPane.showMessageDialog( this, "Class not Found Exception: "+ e.getMessage());
return null;
}
catch(ExceptionInInitializerError e)
{
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
catch(LinkageError e)
{
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
catch( IllegalAccessException e)
{
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
catch (MalformedURLException e)
{
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
catch (InstantiationException e)
{
JOptionPane.showMessageDialog( this, e.getMessage());
return null;
}
}
/**
* @param args
*/
public static void main(String[] args) {
new Experimentor(args);
}
public String getOutputPath() {
return outputDirectory;
}
public JButton getNextBtn() {
return nextBtn;
}
}