package ecologylab.appframework;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.Stack;
import ecologylab.appframework.types.prefs.MetaPrefSet;
import ecologylab.appframework.types.prefs.MetaPrefsTranslationScope;
import ecologylab.appframework.types.prefs.Pref;
import ecologylab.appframework.types.prefs.PrefSet;
import ecologylab.collections.Scope;
import ecologylab.generic.Debug;
import ecologylab.io.Assets;
import ecologylab.io.AssetsRoot;
import ecologylab.io.Files;
import ecologylab.net.ParsedURL;
import ecologylab.platformspecifics.FundamentalPlatformSpecifics;
import ecologylab.serialization.ClassDescriptor;
import ecologylab.serialization.SIMPLTranslationException;
import ecologylab.serialization.SimplTypesScope;
import ecologylab.serialization.XMLTranslationExceptionTypes;
import ecologylab.serialization.formatenums.StringFormat;
/**
* An instance of Environment, which is an application, rather than an applet, or a servlet. The
* Environment mechanism is used to enable the provision of contextual runtime configuration
* parameter services in a way that is independent of the deployment structure.
*
* The SingletonApplicationEnvironment differs from ApplicationEnvironment in that it sets the
* static Environment.the (among other static references). It CANNOT be used in a situation where
* multiple ApplicationEnvironments will operate in the same JVM. It does, however, simplify the use
* of Prefs and other statically accessed application components.
*
* @author Andruid
* @author Zachary O. Toups (zach@ecologylab.net)
*/
public class SingletonApplicationEnvironment extends ApplicationEnvironment implements Environment,
XMLTranslationExceptionTypes, ApplicationPropertyNames
{
public static final String SCREEN_SIZE = "screen_size";
private static final String METAPREFS_XML = "metaprefs.xml";
private static boolean inUse = false;
/** Set of <code>MetaPref</code>s that describe preferences and provide default values. */
MetaPrefSet metaPrefSet;
// must initialize this before subsequent lookup by scope name.
static final SimplTypesScope META_PREFS_TRANSLATION_SCOPE = MetaPrefsTranslationScope.get();
public static enum WindowSize
{
PASS_PARAMS, QUARTER_SCREEN, ALMOST_HALF, NEAR_FULL, FULL_SCREEN
}
public static final String TOP_LEVEL_HEIGHT = "topheight";
public static final String TOP_LEVEL_WIDTH = "topwidth";
static boolean firefoxExists = false;
/**
* Create an ApplicationEnvironment. Create an empty properties object for application parameters.
* <p/>
* No command line argument is processed. Only default preferences are loaded, and processed with
* the default TranslationSpace.
*
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment(String applicationName) throws SIMPLTranslationException
{
this(null, applicationName, null);
}
/**
* Create an ApplicationEnvironment. Load preferences from XML file founds in the
* config/preferences directory. Default preferences will be loaded from preferences.xml. If there
* is a 0th command line argument, that is the name of an additional preferences file.
*
* @param applicationName
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( String applicationName,
SimplTypesScope translationScope,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this(applicationName, translationScope, (SimplTypesScope) null, args, prefsAssetVersion);
}
/**
* Create an ApplicationEnvironment. Load preferences from XML file founds in the
* config/preferences directory. Default preferences will be loaded from preferences.xml. If there
* is a 0th command line argument, that is the name of an additional preferences file.
*
* @param applicationName
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param customPrefs
* TODO
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( String applicationName,
SimplTypesScope translationScope,
Class<? extends Pref<?>>[] customPrefs,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this(applicationName, (Scope<?>) null, translationScope, customPrefs, args, prefsAssetVersion);
}
/**
*
* @param applicationName
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param sessionScope
* @param customPrefs
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( String applicationName,
Scope<?> sessionScope,
SimplTypesScope translationScope,
Class<? extends Pref<?>>[] customPrefs,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this( (Class<?>) null,
applicationName,
sessionScope,
translationScope,
prefsClassArrayToTranslationScope(customPrefs),
args,
prefsAssetVersion);
}
/**
* Create an ApplicationEnvironment. Load preferences from XML file founds in the
* config/preferences directory. Default preferences will be loaded from preferences.xml. If there
* is a 0th command line argument, that is the name of an additional preferences file.
*
* @param applicationName
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param customPrefsTranslationScope
* TODO
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( String applicationName,
SimplTypesScope translationScope,
SimplTypesScope customPrefsTranslationScope,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this( (Class<?>) null,
applicationName,
(Scope<?>) null,
translationScope,
customPrefsTranslationScope,
args,
prefsAssetVersion);
}
/**
* Create an ApplicationEnvironment. Load preferences from XML files found in the
* config/preferences directory. Default preferences will be loaded from preferences.xml. If there
* is a 0th command line argument, that is the name of an additional preferences file.
* <p/>
* The default TranslationSpace, from
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
*
* @param applicationName
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment(String applicationName, String args[])
throws SIMPLTranslationException
{
this(applicationName, (SimplTypesScope) null, (SimplTypesScope) null, args, 0);
}
/**
* Create an ApplicationEnvironment. Get the base for finding the path to the "codeBase" by using
* the package path of the baseClass passed in.
* <p/>
* Load preferences from XML file founds in the codeBase/config/preferences directory. Default
* preferences will be loaded from preferences.xml. If there is a 0th command line argument, that
* is the name of an additional preferences file.
* <p/>
* Also, sets the Assets cacheRoot to the applicationDir().
* <p/>
* The default TranslationSpace, from
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
*
* @param baseClass
* Used for computing codeBase property.
* @param applicationName
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment(Class<?> baseClass, String applicationName, String args[])
throws SIMPLTranslationException
{
this(baseClass, applicationName, null, null, null, args, 0);
}
/**
* Additional constructor to hold the session scope for post processing loaded preferences.
*
* @param applicationName
* @param sessionScope
*/
public SingletonApplicationEnvironment( Class<?> baseClass,
String applicationName,
SimplTypesScope translationScope,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this(baseClass, applicationName, null, translationScope, null, args, prefsAssetVersion);
}
/**
* Create an ApplicationEnvironment.
* <p/>
* Treats the args array like a stack. If any args are missing (based on their format), they are
* skipped.
* <p/>
* The first arg we seek is codeBase. This is a path that ends in slash. It may be a local
* relative path, or a URL-based absolute path.
* <p/>
* The next possible arg is a preferences file. This ends with .xml.
* <p/>
* The next 2 possible args are integers, for graphicsDev and screenSize. graphics_device (screen
* number) to display window. count from 0. screenSize used in TopLevel -- 1 - quarter; 2 - almost
* half; 3; near full; 4 full
* <p/>
* Get the base for finding the path to the "codeBase" by using the package path of the baseClass
* passed in.
* <p/>
* Load preferences from XML file founds in the codeBase/config/preferences directory. Default
* preferences will be loaded from preferences.xml. If there is a 0th command line argument, that
* is the name of an additional preferences file.
* <p/>
* Also, sets the Assets cacheRoot to the applicationDir().
* <p/>
* The default TranslationSpace, from
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
*
* @param baseClass
* Used for computing codeBase property.
* @param applicationName
* Name of the application.
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( Class<?> baseClass,
String applicationName,
Scope sessionScope,
SimplTypesScope translationScope,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
this(baseClass, applicationName, sessionScope, translationScope, null, args, prefsAssetVersion);
}
/**
* Create an ApplicationEnvironment.
* <p/>
* Treats the args array like a stack. If any args are missing (based on their format), they are
* skipped.
* <p/>
* The first arg we seek is codeBase. This is a path that ends in slash. It may be a local
* relative path, or a URL-based absolute path.
* <p/>
* The next possible arg is a preferences file. This ends with .xml.
* <p/>
* The next 2 possible args are integers, for graphicsDev and screenSize. graphics_device (screen
* number) to display window. count from 0. screenSize used in TopLevel -- 1 - quarter; 2 - almost
* half; 3; near full; 4 full
* <p/>
* Get the base for finding the path to the "codeBase" by using the package path of the baseClass
* passed in.
* <p/>
* Load preferences from XML file founds in the codeBase/config/preferences directory. Default
* preferences will be loaded from preferences.xml. If there is a 0th command line argument, that
* is the name of an additional preferences file.
* <p/>
* Also, sets the Assets cacheRoot to the applicationDir().
* <p/>
* The default TranslationSpace, from
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
*
* @param baseClass
* Used for computing codeBase property.
* @param applicationName
* Name of the application.
* @param translationScope
* TranslationSpace used for translating preferences XML. If this is null,
* {@link ecologylab.oodss.messages.DefaultServicesTranslations
* ecologylab.oodss.message.DefaultServicesTranslations} will be used.
* @param customPrefs
* An array of Pref subclasses that are used for this specific application. These classes
* will be automatically composed into a special translation scope used for translating
* prefs for the application. Note that translationScope is NOT used for translating the
* application prefs, but is still required for other translations in the application.
* @param args
* The args array, which is treated as a stack with optional entries. They are: *) JNLP
* -- if that is the launch method *) preferences file if you are running in eclipse.
* Relative to CODEBASE/config/preferences/ *) graphics_device (screen number) *)
* screen_size (used in TopLevel -- 1 - quarter; 2 - almost half; 3; near full; 4 full)
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
public SingletonApplicationEnvironment( Class<?> baseClass,
String applicationName,
Scope<?> sessionScope,
SimplTypesScope translationScope,
SimplTypesScope customPrefsTranslationScope,
String args[],
float prefsAssetVersion) throws SIMPLTranslationException
{
super(baseClass,
applicationName,
sessionScope,
translationScope,
customPrefsTranslationScope,
args,
prefsAssetVersion);
inUse = true;
// this is the one and only singleton Environment
Environment.the.set(this);
PropertiesAndDirectories.setApplicationName(applicationName);
}
/**
* Sets the applicationName for PropertiesAndDirectories.
*
* @see ecologylab.appframework.ApplicationEnvironment#setApplicationName(java.lang.String)
*/
@Override
protected void setApplicationName(String applicationName)
{
super.setApplicationName(applicationName);
PropertiesAndDirectories.setApplicationName(applicationName);
}
@Override
protected void processArgsAndPrefs(Class<?> baseClass, SimplTypesScope translationScope,
float prefsAssetVersion) throws SIMPLTranslationException
{
String arg;
processPrefs(baseClass, translationScope, argStack, prefsAssetVersion);
Debug.initialize();
arg = pop(argStack);
if (arg == null)
return;
try
{
int screenNum = Integer.parseInt(arg);
Pref.useAndSetPrefInt("graphics_device", screenNum);
}
catch (NumberFormatException e)
{
argStack.push(arg);
}
try
{
arg = pop(argStack);
if (arg == null)
return;
Pref.useAndSetPrefInt(SCREEN_SIZE, WindowSize.valueOf(arg.toUpperCase()).ordinal());
}
catch (IllegalArgumentException e)
{
argStack.push(arg);
}
if (Pref.lookupInt(SCREEN_SIZE) == 0)
{
try
{
arg = pop(argStack);
if (arg == null)
return;
Pref.useAndSetPrefInt(TOP_LEVEL_WIDTH, Integer.parseInt(arg));
arg = pop(argStack);
if (arg == null)
return;
Pref.useAndSetPrefInt(TOP_LEVEL_HEIGHT, Integer.parseInt(arg));
}
catch (IllegalArgumentException e)
{
argStack.push(arg);
}
}
}
/**
* request User's prefSet from the preferenceServlet and return the prefSetXML string.
*
* @author eunyee
* @param prefServlet
* @param translationScope
* TODO
* @param uid
* @return
*/
@Override
protected PrefSet requestPrefFromServlet(String prefServlet, SimplTypesScope translationScope)
{
System.out.println("retrieving preferences set from servlet: " + prefServlet);
/*
* try { ParsedURL purl = new ParsedURL(new URL(prefServlet));
*
* PrefSet prefSet = (PrefSet) ElementState.translateFromXML(purl, PrefTranslations.get());
* return prefSet; } catch (MalformedURLException e1) { // TODO Auto-generated catch block
* e1.printStackTrace(); } catch (XmlTranslationException e) { // TODO Auto-generated catch
* block e.printStackTrace(); } return null;
*/
try
{
URL url = new URL(prefServlet);
URLConnection connection = url.openConnection();
// specify the content type that binary data is sent
connection.setRequestProperty("Content-Type", "text/xml");
// define a new BufferedReader on the input stream
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// receive data from the servlet
String prefSetXML = in.readLine();
PrefSet prfs = null;
try
{
prfs = PrefSet.loadFromCharSequence(prefSetXML, translationScope);
System.out.println("Prefs loaded From Servlet:: ");
if (prfs != null)
SimplTypesScope.serialize(prfs, System.out, StringFormat.XML);
System.out.println(" --- End Prefs");
}
catch (SIMPLTranslationException e)
{
e.printStackTrace();
}
in.close();
return prfs;
}
catch (IOException e)
{
warning("not a <pref_set> servlet URL: " + prefServlet);
}
return null;
}
/**
* Load MetaPrefs and Prefs, if possible
*
* @param baseClass
* @param translationScope
* @param argStack
* @param prefsAssetVersion
* TODO
* @throws SIMPLTranslationException
*/
private void processPrefs(Class<?> baseClass, SimplTypesScope translationScope,
Stack<String> argStack, float prefsAssetVersion) throws SIMPLTranslationException
{
LaunchType launchType = LaunchType.ECLIPSE; // current default
// look for launch method identifier in upper case
String arg = pop(argStack);
if (arg != null)
{
String uc = arg.toUpperCase();
if ("JNLP".equals(uc))
{ // tells us how we were launched: e.g., JNLP, ECLIPSE, ...
launchType = LaunchType.JNLP;
}
else if ("STUDIES".equals(uc))
{
launchType = LaunchType.STUDIES;
}
else
{
// TODO -- recognize JAR here !!!
argStack.push(arg);
}
LAUNCH_TYPE_PREF.setValue(launchType);
}
println("LaunchType = " + launchType);
this.launchType = launchType;
// look for codeBase path
arg = pop(argStack);
// read perhaps meta-preferences and surely preferences from application data dir
File applicationDir = PropertiesAndDirectories.thisApplicationDir();
ParsedURL applicationDataPURL = new ParsedURL(applicationDir);
prefsPURL = applicationDataPURL.getRelative("preferences/prefs.xml");
debugA("prefsPURL= " + prefsPURL);
System.out.println("arg: " + arg);
switch (launchType)
{
case STUDIES:
case JNLP:
// next arg *should* be code base
if ((arg != null) && arg.endsWith("/"))
{
// JNLP only! (as of now)
// right now this only works for http://
ParsedURL codeBase = ParsedURL.getAbsolute(arg, "Setting up codebase");
this.setCodeBase(codeBase);
// XXX is this right?
final String host = codeBase.host();
if ("localhost".equals(host) || "127.0.0.1".equals(host))
{
debug("launched from localhost. must be a developer.");
LAUNCH_TYPE_PREF.setValue(LaunchType.LOCAL_JNLP);
}
SIMPLTranslationException metaPrefSetException = null;
ParsedURL metaPrefsPURL = null;
try
{
AssetsRoot prefAssetsRoot = new AssetsRoot(this, PREFERENCES, null);
File metaPrefsFile = Assets.getAsset( prefAssetsRoot,
METAPREFS_XML,
"prefs",
null,
false,
prefsAssetVersion);
metaPrefsPURL = new ParsedURL(metaPrefsFile);
metaPrefSet = MetaPrefSet.load(metaPrefsFile, translationScope);
println("OK: loaded MetaPrefs from " + metaPrefsFile);
}
catch (SIMPLTranslationException e)
{
metaPrefSetException = e;
}
catch (Exception e)
{
e.printStackTrace();
}
// from supplied URL instead of from here
try
{
debugA("Considering prefSet=" + prefSet + "\tprefsPURL=" + prefsPURL);
if (prefSet == null) // Normal Case
{
prefSet = PrefSet.load(prefsPURL, translationScope);
if (prefSet != null)
println("OK: Loaded Prefs from " + prefsPURL);
else
println("No Prefs to load from " + prefsPURL);
}
if (metaPrefSetException != null)
{
warning("Couldn't load MetaPrefs:");
metaPrefSetException.printTraceOrMessage(this, "MetaPrefs", metaPrefsPURL);
println("\tContinuing.");
}
}
catch (SIMPLTranslationException e)
{
if (metaPrefSetException != null)
{
error("Can't load MetaPrefs or Prefs. Quitting.");
metaPrefSetException.printTraceOrMessage(this, "MetaPrefs", metaPrefsPURL);
e.printTraceOrMessage(this, "Prefs", prefsPURL);
}
else
{
// meta prefs o.k. we can continue
warning("Couldn't load Prefs:");
e.printTraceOrMessage(this, "Prefs", prefsPURL);
println("\tContinuing.");
}
}
debugA("argStack.size() = " + argStack.size());
if (argStack.size() > 0)
{
String prefSpec = "";
if (arg.startsWith("http://"))
{
// PreferencesServlet
prefSpec = pop(argStack);
if (prefSpec != null)
{
// load URLEncoded prefs XML straight from the argument
PrefSet JNLPPrefSet = loadPrefsFromJNLP(prefSpec);
if (JNLPPrefSet != null)
{
if (prefSet == null)
prefSet = JNLPPrefSet;
else
prefSet.append(JNLPPrefSet);
}
else
{ // if we got args straight from jnlp, then continue
if (JNLPPrefSet != null)
prefSpec = pop(argStack);
if (prefSpec != null)
{
PrefSet servletPrefSet = requestPrefFromServlet(prefSpec, translationScope);
if (servletPrefSet == null)
error("incorrect prefXML string returned from the servlet=" + prefSpec);
else
{
if (prefSet == null)
prefSet = servletPrefSet;
else
prefSet.append(servletPrefSet);
}
}
}
}
}
}
}
else
{
error("No code base argument :-( Can't load preferences.");
}
break;
case ECLIPSE:
case JAR:
// NB: This gets executed even if arg was null!
File localCodeBasePath = deriveLocalFileCodeBase(baseClass); // sets codeBase()!
argStack.push(arg);
// AssetsRoot prefAssetsRoot = new AssetsRoot(Assets.getAssetsRoot().getRelative(PREFERENCES),
// Files.newFile(PropertiesAndDirectories.thisApplicationDir(), PREFERENCES));
// Assets.downloadZip(prefAssetsRoot, "prefs", null, false, prefsAssetVersion);
SIMPLTranslationException metaPrefSetException = null;
File metaPrefsFile = new File(localCodeBasePath, ECLIPSE_PREFS_DIR + METAPREFS_XML);
ParsedURL metaPrefsPURL = new ParsedURL(metaPrefsFile);
try
{
metaPrefSet = MetaPrefSet.load(metaPrefsPURL, translationScope);
println("OK: Loaded MetaPrefs from: " + metaPrefsFile);
}
catch (SIMPLTranslationException e)
{
metaPrefSetException = e;
}
// load the application dir prefs from this machine
// (e.g., c:\Documents and Settings\andruid\Application
// Data\combinFormation\preferences\prefs.xml
// these are the ones that get edited interactively!
prefSet = PrefSet.load(prefsPURL, translationScope);
if (prefSet != null)
println("Loaded Prefs from: " + prefsPURL);
else
println("No Prefs to load from: " + prefsPURL);
// now seek the path to an application specific xml preferences file
arg = pop(argStack);
// if (arg == null)
// return;
if (arg != null)
{
// load preferences specific to this invocation
if (arg.endsWith(".xml"))
{
File argPrefsFile = new File(localCodeBasePath, ECLIPSE_PREFS_DIR + arg);
ParsedURL argPrefsPURL = new ParsedURL(argPrefsFile);
try
{
PrefSet argPrefSet = PrefSet.load(argPrefsPURL, translationScope);
if (metaPrefSetException != null)
{
warning("Couldn't load MetaPrefs:");
metaPrefSetException.printTraceOrMessage(this, "MetaPrefs", metaPrefsPURL);
println("\tContinuing.");
}
if (argPrefSet != null)
{
println("OK: Loaded Prefs from: " + argPrefsFile);
if (prefSet != null)
prefSet.addPrefSet(argPrefSet);
else
prefSet = argPrefSet;
}
else
{
println("");
String doesntExist = argPrefsFile.exists() ? "" : "\n\tFile does not exist!!!\n\n";
println("ERROR: Loading Prefs from: " + argPrefsFile + doesntExist);
}
}
catch (SIMPLTranslationException e)
{
if (metaPrefSetException != null)
{
error("Can't load MetaPrefs or Prefs. Quitting.");
metaPrefSetException.printTraceOrMessage(this, "MetaPrefs", metaPrefsPURL);
e.printStackTrace();
throw e;
}
// meta prefs o.k. we can continue without having loaded Prefs now
e.printTraceOrMessage(this, "Couldn't load Prefs", argPrefsPURL);
println("\tContinuing.");
}
}
else
argStack.push(arg);
}
else
argStack.push(arg); // let the next code handle returning.
break;
}
System.out.println("Printing Prefs:\n");
try
{
if (prefSet != null)
SimplTypesScope.serialize(prefSet, System.out, StringFormat.XML);
}
catch (SIMPLTranslationException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("\nPrefs Printed");
if (prefSet != null)
postProcessPrefs(prefSet);
}
/**
* Look for pref Ops, if delayed: setup their timers, and also set scope for their ops.
*
* @param prefSet
*/
private void postProcessPrefs(PrefSet prefSet)
{
if (sessionScope == null)
return;
for (Pref<?> pref : prefSet.values())
if (pref != null)
pref.postLoadHook(sessionScope);
}
private PrefSet loadPrefsFromJNLP(String prefSpec)
{
PrefSet prefSet = null;
debugA("loadPrefsFromJNLP()");
if (prefSpec.startsWith("%3Cpref_set"))
{
try
{
String decodedPrefsXML = URLDecoder.decode(prefSpec, "UTF-8");
debugA("Loading prefs from JNLP: " + decodedPrefsXML);
for (ClassDescriptor c : translationScope.getClassDescriptors())
{
debugA(c.toString());
}
prefSet = PrefSet.loadFromCharSequence(decodedPrefsXML, translationScope);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
catch (SIMPLTranslationException e)
{
e.printStackTrace();
}
}
return prefSet;
}
/**
* Get the user.dir property. Form a path from it, ending in slash. See if there is path within
* that that includes the package of baseClass. If so, remove that component from the path.
*
* Form a File from this path, and a ParsedURL from the file. Set codeBase to this ParsedURL.
*
* @param baseClass
* Class of the subclass of this that is the main program that was executed.
*
* @return File that corresponds to the path of the local codeBase.
*/
@Override
protected File deriveLocalFileCodeBase(Class<?> baseClass)
{
// setup codeBase
if (baseClass == null)
baseClass = this.getClass();
Package basePackage = baseClass.getPackage();
String packageName = basePackage.getName();
String packageNameAsPath = packageName.replace('.', Files.sep);
String pathName = System.getProperty("user.dir") + Files.sep;
File path = new File(pathName);
String pathString = path.getAbsolutePath();
// println("looking for " + packageNameAsPath +" in " + pathString);
int packageIndex = pathString.lastIndexOf(packageNameAsPath);
if (packageIndex != -1)
{
pathString = pathString.substring(0, packageIndex);
path = new File(pathString + Files.sep);
}
codeBase = new ParsedURL(path);
println("codeBase=" + codeBase);
return path;
}
/**
* @see ecologylab.appframework.Environment#runtimeEnv()
*/
@Override
public int runtimeEnv()
{
return APPLICATION;
}
/**
* @see ecologylab.appframework.Environment#status(String)
*/
@Override
public void showStatus(String s)
{
System.out.println(s);
}
/**
* @see ecologylab.appframework.Environment#status(String)
*/
@Override
public void status(String msg)
{
if (msg != null)
showStatus(msg);
}
/**
* @see ecologylab.appframework.Environment#docBase() return the current working directory of the
* application which is "c:\web\code\java\cm"
*/
@Override
public ParsedURL docBase()
{
ParsedURL purl = new ParsedURL(new File(System.getProperty("user.dir")));
return purl;
}
@Override
public ParsedURL preferencesDir()
{
ParsedURL codeBase = codeBase();
ParsedURL purl = codeBase.getRelative(ECLIPSE_PREFS_DIR, "forming preferences dir");
return purl;
}
static final String FIREFOX_PATH_WINDOWS = "C:\\Program Files\\Mozilla Firefox\\firefox.exe";
static final String FIREFOX_PATH_WINDOWS_64 = "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe";
static final String FIREFOX_PATH_VIRT = "C:\\Program Files (x86)\\Microsoft Application Virtualization Client\\sfttray.exe";
// TODO -- use "open" on the mac!!!
static final String FIREFOX_PATH_MAC = "/Applications/Firefox.app/Contents/MacOS/firefox";
// static final String FIREFOX_PATH_MAC = null;
static final String SAFARI_PATH_MAC = "/Applications/Safari.app/Contents/MacOS/Safari";
static final String FIREFOX_PATH_LINUX = "/usr/bin/firefox";
static final String IE_PATH_WINDOWS = "C:\\Program Files\\Internet Explorer\\IEXPLORE.EXE";
static String browserPath;
/**
* Get the operating system dependent path to a suitable web browser for navigating to a web page.
* This is also dependent on what web browser(s) the user has installed. In particular, we use
* Firefox if it is in its normal place!
*
* @return String that specifies the OS and browser-specific command.
*/
static String getBrowserPath()
{
int os = PropertiesAndDirectories.os();
String result = browserPath;
if (result == null)
{
switch (os)
{
case PropertiesAndDirectories.XP:
case PropertiesAndDirectories.VISTA_AND_7:
if (!Pref.lookupBoolean("navigate_with_ie"))
result = FIREFOX_PATH_WINDOWS;
if (result != null)
{
File existentialTester = new File(result);
if (!existentialTester.exists())
{
result = FIREFOX_PATH_WINDOWS_64;
existentialTester = new File(result);
if (!existentialTester.exists())
{
result = IE_PATH_WINDOWS;
existentialTester = new File(result);
if (!existentialTester.exists())
result = null;
}
}
}
break;
case PropertiesAndDirectories.MAC:
result = "/usr/bin/open";
break;
default:
error(PropertiesAndDirectories.getOsName(), "go(ParsedURL) not supported");
break;
}
if (result != null)
{
browserPath = result;
}
}
return result;
}
static String[] cachedNavigateArgs;
/**
* Get the operating system dependent path to a suitable web browser for navigating to a web page.
* This is also dependent on what web browser(s) the user has installed. In particular, we use
* Firefox if it is in its normal place!
*
* @return String that specifies the OS and browser-specific command.
*/
static String[] getNavigateArgs()
{
int os = PropertiesAndDirectories.os();
String[] result = cachedNavigateArgs;
if (result == null)
{
switch (os)
{
case PropertiesAndDirectories.XP:
case PropertiesAndDirectories.VISTA_AND_7:
String path = null;
if (!Pref.lookupBoolean("navigate_with_ie"))
path = FIREFOX_PATH_WINDOWS;
if (path != null)
{
File existentialTester = new File(path);
firefoxExists = existentialTester.exists();
if (!firefoxExists)
{
path = FIREFOX_PATH_WINDOWS_64;
existentialTester = new File(path);
firefoxExists = existentialTester.exists();
}
if (firefoxExists)
{ // cool! firefox
result = new String[3];
result[0] = path;
result[1] = "-new-tab";
} else {
//Use the SCC Virtualization Path
path = FIREFOX_PATH_VIRT;
existentialTester = new File(path);
firefoxExists = existentialTester.exists();
if(firefoxExists)
{
result = new String[5];
result[0] = path;
result[1] = "/launch";
result[2] = "\"Mozilla Firefox 11\"";
result[3] = "-new-tab";
}
}
}
if (result == null)
{
path = IE_PATH_WINDOWS;
File existentialTester = new File(path);
if (existentialTester.exists())
{
result = new String[2];
result[0] = path;
}
}
break;
case PropertiesAndDirectories.MAC:
result = new String[4];
result[0] = "/usr/bin/open";
result[1] = "-a";
result[2] = "firefox";
firefoxExists = true;
break;
case PropertiesAndDirectories.LINUX:
result = new String[2];
result[0] = FIREFOX_PATH_LINUX;
firefoxExists = true;
break;
default:
error(PropertiesAndDirectories.getOsName(), "go(ParsedURL) not supported");
break;
}
if (result != null)
{
cachedNavigateArgs = result;
}
}
return result;
}
/**
* Returns true if firefox was found on this system.
* @return
*/
@Override
public boolean hasFirefox()
{
getNavigateArgs();//sets firefoxExists if true
return firefoxExists;
}
/**
* Navigate to the purl using the best browser we can find.
*
* @param purl
* @param frame
*/
@Override
public void navigate(ParsedURL purl, String frame)
{
String[] navigateArgs = getNavigateArgs();
if (navigateArgs != null && purl != null)
{
String purlString = purl.toString();
int numArgs = navigateArgs.length;
navigateArgs[numArgs - 1] = purlString;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < numArgs; i++)
sb.append(navigateArgs[i]).append(' ');
Debug.println("navigate: " + sb);
try
{
Process p = Runtime.getRuntime().exec(navigateArgs);
}
catch (IOException e)
{
error("navigate() - caught exception: ");
e.printStackTrace();
}
}
else
error("navigate() - Can't find browser to navigate to.");
}
@Override
public int browser()
{
return APPLICATION;
}
/**
* Called at the end of an invocation. Calls System.exit(code).
*
* @param code
* -- 0 for normal. other values are application specific.
*/
@Override
public void exit(int code)
{
System.exit(code);
}
public static boolean isInUse()
{
return inUse;
}
public static boolean runningInEclipse()
{
return LaunchType.ECLIPSE == LAUNCH_TYPE_PREF.value();
}
public static boolean runningLocalhost()
{
return LaunchType.LOCAL_JNLP == LAUNCH_TYPE_PREF.value();
}
/**
* Create and show an editor for preferences, iff the MetaPrefSet and PrefSet are non-null. If the
* PrefSet is null, a new empty one will be created for the editor to use.
*
* @return
*/
public Object createPrefsEditor(final boolean createJFrame, final boolean isStandalone)
{
Object result = null;
if (metaPrefSet != null)
{
if (prefSet == null)
prefSet = new PrefSet();
result = FundamentalPlatformSpecifics.get().getOrCreatePrefsEditor(metaPrefSet, prefSet, prefsPURL, createJFrame, isStandalone);
}
return result;
}
/**
* Create and show an editor for preferences, iff the MetaPrefSet and PrefSet are non-null. If the
* PrefSet is null, a new empty one will be created for the editor to use.
*
* @return
*/
public Object createPrefsEditor()
{
return this.createPrefsEditor(true, false);
}
/**
*
* @return MetaPrefSet for this application, loaded from standard locations.
*/
protected MetaPrefSet metaPrefSet()
{
return metaPrefSet;
}
@Override
public String getApplicationName()
{
return PropertiesAndDirectories.applicationName;
}
}