package com.adaptrex.tools.environment;
import static com.adaptrex.tools.Tools.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.ini4j.Ini;
import com.adaptrex.tools.Tools;
import com.adaptrex.tools.framework.javascript.AdaptrexJS;
import com.adaptrex.tools.framework.javascript.ExtJS;
import com.adaptrex.tools.framework.javascript.ICompileService;
import com.adaptrex.tools.framework.javascript.IDownloadService;
import com.adaptrex.tools.framework.javascript.JavaScriptFramework;
import com.adaptrex.tools.framework.javascript.SenchaTouch;
import com.adaptrex.tools.log.ILogService;
import com.adaptrex.tools.log.Log;
import com.adaptrex.tools.webapp.IWebappService;
import com.adaptrex.tools.webapp.Webapp;
import com.google.inject.Inject;
import com.google.inject.Singleton;
@Singleton
public class EnvironmentService implements IEnvironmentService {
private String userHome = System.getProperty("user.home");
private String configPath = userHome + "/.adaptrex.config";
private Environment env;
public IWebappService webappService;
public IDownloadService downloadService;
public ILogService logService;
public ICompileService compileService;
@Inject
public EnvironmentService(IWebappService webappService, IDownloadService downloadService,
ICompileService compileService, ILogService logService) {
this.webappService = webappService;
this.downloadService = downloadService;
this.logService = logService;
this.compileService = compileService;
}
/*
* Get the configured environment
*/
@Override
public Environment getEnvironment() {
return this.env;
}
/*
* Initial load of environment (without suppressing errors)
*/
@Override
public boolean initializeEnvironment() throws IOException {
return initializeEnvironment(false);
}
/*
* Initial load of environment.
*
* When we start up the tools, we should learn about the environment. This includes:
* - Get the path of the sencha cmd folder
* - Get the path of the webroot (and weblib) folders
* - Get the list of frameworks available in the weblib
* - Get the list of webapps that have been configured in the environment
*
* In some cases, we suppress errors if we are running a command that may be fixing the error
*/
@Override
public boolean initializeEnvironment(boolean suppressErrors) throws IOException {
if (this.env != null) return true;
/*
* Create our environment
*/
this.env = new Environment();
/*
* Get our settings file... if one doesn't exist, create it
*/
File configFile = new File(configPath);
if (!configFile.exists()) saveEnvironment();
/*
* Create collections to hold our settings, frameworks and webapps for later processing
*/
Ini ini = new Ini();
ini.load(new FileReader(configFile));
/*
* Get info about our webroot and sencha cmd paths
*/
Ini.Section settingsSection = ini.get(Environment.SETTINGS);
String webrootPath = settingsSection.get(Environment.WEBROOT_PATH);
String cmdPath = settingsSection.get(Environment.SENCHA_CMD_PATH);
/*
* Get our list of webapps
*/
List<String> webappPaths = new ArrayList<String>();
Map<String, String> webappPathMap = ini.get(Environment.WEBAPPS);
if (webappPathMap != null)
for (String key : webappPathMap.keySet())
webappPaths.add(webappPathMap.get(key));
/*
* Make sure Sencha cmd is configured. If sencha cmd isn't already configured in the settings
* file, search for one in the common path. If we only have one version of sencha cmd installed
* assume that's the one we want to use.
*/
if (cmdPath == null) {
List<File> cmds = Tools.searchForFile(userHome + "/bin/Sencha/Cmd", "sencha.jar");
if (cmds.size() == 0) {
logService.log(Log.WARNING, "Sencha Cmd Is Not Configured",
"Sencha Cmd is currently only required when running 'adaptrex compile'." + CR + CR +
"Sencha Cmd could not be found in a standard location and could" + CR +
"not be automatically configured by Adaptrex Tools. If you do" + CR +
"not have Sencha Cmd installed, download and install it from " + CR +
"http://www.sencha.com/products/sencha-cmd/download" + CR + CR +
"If Sencha Cmd is already installed on your system, run" + CR +
"\"adaptrex configure environment -c=/path/to/sencha/cmd/folder\""
);
} if (cmds.size() == 1) {
cmdPath = cmds.get(0).getParent();
logService.log(Log.INFO, "Sencha Cmd Automatically Configured",
"Sencha Cmd has not been previously configured for your environment. Adaptrex" + CR +
"Tools was able to find and and automatically configured Sencha Cmd at " + CR +
cmdPath);
} else {
List<String> versions = new ArrayList<String>();
for (File cmd : cmds) versions.add(TAB + cmd.getParent());
logService.log(Log.WARNING, "Sencha Cmd Is Not Configured",
"Sencha Cmd is currently only required when running 'adaptrex compile'." + CR + CR +
"Sencha Cmd could not be found in a standard location and could not be" + CR +
"automatically configured by Adaptrex Tools. To configure a specific" + CR +
"version for use with Adaptrex tools, run one of the following:" + CR +
StringUtils.join(versions, CR));
}
}
/*
* Make sure the cmd folder is configured properly
*/
if (cmdPath != null && !(new File(cmdPath + "/sencha.jar")).exists()) {
logService.log(Log.WARNING, "Invalid Sencha Cmd folder",
cmdPath + "Is not a valid Sencha Cmd folder. Run " + CR +
"\"adaptrex config environment\" to set the correct path to Sencha Cmd" + CR
);
}
/*
* If we don't have a webroot or sencha cmd, drop out now
*/
if (webrootPath == null || cmdPath == null) return true;
/*
* Update our environment with the cmd and webrot
*/
env.setCmdPath(cmdPath);
env.setWebrootPath(webrootPath);
/*
* Make sure webroot exists
*/
File weblib = new File(webrootPath + "/weblib");
if (!suppressErrors) {
if (!weblib.exists()) {
logService.log(Log.WARNING, "Weblib folder missing",
"The configured webroot at " + webrootPath + CR +
"could not be found. Please run \"adaptrex configure environment\" to " + CR +
"update your weblib path"
);
}
}
/*
* Update the list of weblibs
*/
if (weblib.exists()) {
for (String folderName : weblib.list()) {
if (folderName.startsWith("adaptrex")) {
AdaptrexJS fw = new AdaptrexJS(env.getWebrootPath() + "/weblib/" + folderName);
if (fw != null && fw.getVersion() != null)
this.env.getAdaptrexFrameworks().put(folderName,fw);
}
if (folderName.startsWith("ext")) {
ExtJS fw = new ExtJS(env.getWebrootPath() + "/weblib/" + folderName);
if (fw != null && fw.getVersion() != null)
this.env.getExtFrameworks().put(folderName,fw);
}
if (folderName.startsWith("sencha")) {
SenchaTouch fw = new SenchaTouch(env.getWebrootPath() + "/weblib/" + folderName);
if (fw != null && fw.getVersion() != null)
this.env.getSenchaTouchFrameworks().put(folderName,fw);
}
}
}
/*
* Make sure we have the proper set of frameworks
*/
if (!suppressErrors) {
List<String> missing = new ArrayList<String>();
if (this.env.getAdaptrexFrameworks().size() == 0) missing.add("AdaptrexJS");
if (this.env.getExtFrameworks().size() == 0 && this.env.getSenchaTouchFrameworks().size() == 0)
missing.add("ExtJS/Sencha Touch");
if (missing.size() > 0) {
String missingString = StringUtils.join(missing, " and ");
logService.log(Log.WARNING, "Missing frameworks",
webrootPath + "/weblib is missing the required" + CR + missingString + " folder" + CR + CR +
"Your weblib path has been set but you will need to make the" + CR +
"required frameworks available by doing one fo the following: " + CR +
TAB + "- Run \"adaptrex configure environment\" again to specify the correct folder" + CR +
TAB + "- Manually placing the framework folders in the weblib folder" + CR +
TAB + "- Run \"adaptrex install\" to automatically download and install the frameworks."
);
}
}
/*
* Load Webapps and confirm that the webapp actually exists on the machine
*/
for (String webappPath : webappPaths) {
Webapp webapp = webappService.loadWebapp(webappPath);
if (webapp != null) addWebappToEnvironment(webapp);
else logService.log(Log.WARNING, "Couldn't find webapp @ " + webappPath);
}
return true;
}
/*
* Get a webapp (without suppressing warnings)
*/
@Override
public Webapp getWebapp(String path) {
return getWebapp(path, false);
}
/*
* Get a webapp (optionally suppress warnings)
*/
@Override
public Webapp getWebapp(String path, boolean suppressWarning) {
Webapp webapp = env.getWebapps().get(path.replace("\\/", "."));
if (!suppressWarning && webapp == null)
logService.log(Log.ERROR, "Could not find webapp at \"" + path + "\"");
return webapp;
}
/*
* Remove a webapp from the configuration
*/
@Override
public boolean deleteWebapp(Webapp webapp, boolean deleteFiles) throws IOException {
env.getWebapps().values().remove(webapp);
logService.log(Log.SUCCESS, "Webapp \"" + webapp.getName() +
"\" has been removed from your configuration");
this.saveEnvironment();
return true;
}
/*
* Import a webapp at a specific path. This assumes the webapp is previously configured
*/
@Override
public Webapp importWebapp(String path) throws IOException {
return importWebapp(path, null, null, null, null,
null, null, null, null, null, null, null, null);
}
/*
* Import an existing webapp and add configurations for adaptrex, ext and sencha touch.
*/
@Override
public Webapp importWebapp(String path, String name,
String globalFolder, String globalNamespace, String basePackage,
String adaptrexFolder, String extFolder, String senchaTouchFolder,
String presentation, String orm, String di, String extTheme, String senchaTouchTheme
) throws IOException {
/*
* Make sure we don't already have a webapp at this path
*/
Webapp existing = getWebapp(path, true);
if (existing != null) {
logService.log(Log.ERROR, "Webapp already exists",
"A webapp at " + path + CR +
"is already configured in your environment");
return null;
}
/*
* Make sure we've got a valid webapp folder path
*/
File webappFolder = new File(path);
if (!webappFolder.exists()) {
logService.log(Log.ERROR, "Path not found", path + " is not a valid folder");
return null;
}
/*
* Make sure we have a valid adaptrex webapp at this path
*/
File webappSrcFolder = new File(path + "/src/main/webapp");
if (!webappSrcFolder.exists()) {
logService.log(Log.ERROR, "Invalid webapp",
path + " is not a valid Adaptrex webapp." + CR +
"Adaptrex Tools requires your web contents at src/main/webapp.");
return null;
}
/*
* Check for an existing webapp config file
*/
Webapp webapp = webappService.loadWebapp(path);
if (webapp == null) {
webapp = new Webapp();
webapp.setFullPath(path);
/*
* If we're creating a new webapp, we need to know everything
* about the settings for this webapp
*/
List<String> missingConfigs = new ArrayList<String>();
if (basePackage == null) missingConfigs.add("base-package");
if (orm == null) missingConfigs.add("orm");
if (presentation == null) missingConfigs.add("presentation");
if (missingConfigs.size() > 0) {
String missingString = "";
for (String missingConfig : missingConfigs)
missingString += Tools.TAB + missingConfig + CR;
logService.log(Log.ERROR, "Missing Configuration Options",
"Your webapp is missing the following required configurations: " + CR +
missingString
);
return null;
}
}
/*
* Keep track of previously configured or missing settings
*/
List<String> previouslyConfigured = new ArrayList<String>();
/*
* If we're setting name, make sure it's not already configured
*/
boolean hasName = true;
if (webapp.getName() == null) {
if (name == null) hasName = false;
else webapp.setName(name);
} else if (name != null) {
previouslyConfigured.add(TAB + "-p=\"" + webapp.getFullPath() + "\" -n=\"" + name + "\"");
}
/*
* If we're setting adaptrex, make sure it's not already configured
*/
boolean hasAdaptrex = true;
if (webapp.getAdaptrex() == null) {
if (adaptrexFolder == null) hasAdaptrex = false;
else hasAdaptrex = webappService.setAdaptrexJS(webapp, adaptrexFolder);
} else if (adaptrexFolder != null) {
String opt = "-a" +
(adaptrexFolder.equals(JavaScriptFramework.DEFAULT) ? "" : "=" + adaptrexFolder);
previouslyConfigured.add(TAB + "-p=\"" + webapp.getFullPath() + "\" " + opt);
}
/*
* If we're setting extjs, make sure it's not already configured
*/
boolean hasExt = true;
if (webapp.getExt() == null) {
if (extFolder == null) hasExt = false;
else hasExt = webappService.setExtJS(webapp, extFolder);
} else if (extFolder != null) {
String opt = "-e" +
(extFolder.equals(JavaScriptFramework.DEFAULT) ? "" : "=" + extFolder);
previouslyConfigured.add(TAB + "-p=\"" + webapp.getFullPath() + "\" " + opt);
}
/*
* If we're setting adaptrexjs, make sure it's not already configured
*/
boolean hasSenchaTouch = true;
if (webapp.getSenchaTouch() == null) {
if (senchaTouchFolder == null) hasSenchaTouch = false;
else hasSenchaTouch = webappService.setSenchaTouch(webapp, senchaTouchFolder);
} else if (senchaTouchFolder != null) {
String opt = "-s" +
(senchaTouchFolder.equals(JavaScriptFramework.DEFAULT) ? "" : "=" + senchaTouchFolder);
previouslyConfigured.add(TAB + "-p=\"" + webapp.getFullPath() + "\" " + opt);
}
/*
* If we don't at a name, adaptrex or Ext/SenchaTouch, drop out
*/
if (!hasName) logService.log(Log.ERROR, "Missing Webapp Name",
"The webapp you are importing does not have a name already configured. In order to" + CR +
"import this webapp into your environment, you need to specify a name by including" + CR +
"the following option with your import command:" + CR +
TAB + "-sn=\"Webapp Name\""
);
if (!hasAdaptrex) logService.log(Log.ERROR, "Missing Adaptrex Folder",
"The webapp you are importing does not have an AdaptrexJS folder already configured." + CR +
"In order to import this webapp into your environment you need to specify an AdaptrexJS" + CR +
"version to use by including one of the following option with your import command:" + CR +
TAB + "-a=adaptrex-js-1.0.0" + CR +
TAB + "-a (setting this option without an explicit folder uses your only AdaptrexJS folder)"
);
if (!hasExt && !hasSenchaTouch) logService.log(Log.ERROR, "Missing ExtJS or Sencha Touch Folder",
"The webapp you are importing does not have an ExtJS or SenchaTouch folder already configured." + CR +
"In order to import this webapp into your environment you need to specify an ExtJS or Sencha Touch" + CR +
"version to use by including one of the following option with your import command:" + CR +
TAB + "-e=ext-js-4.1.1a" + CR +
TAB + "-e (setting this option without an explicit folder uses your only ExtJS folder)" + CR +
TAB + "-e=sencha-touch-2.1.0" + CR +
TAB + "-e (setting this option without an explicit folder uses your only Sencha Touch folder)"
);
if (!hasName || !hasAdaptrex || (!hasExt && !hasSenchaTouch)) return null;
/*
* If we have some previously configured settings, notify the user that we are not changing
* them and that they will need to manually run the configuration tools to change them
*/
if (previouslyConfigured.size() > 0) {
String cmds = StringUtils.join(previouslyConfigured, CR);
logService.log(Log.WARNING, "Webapp previously configured",
"The webapp at " + path + " has successfully" + CR +
"been added to your environment but the webapp itself has been previously" + CR +
"configured. The existing webapp configuration has been retained to ensure" + CR +
"compatibility. If you still wish to change the configuration of the existing " + CR +
"webapp, run one or more of the of the following commands:" + CR +
cmds
);
}
/*
* Save the new webapp and also add it to the environment
*/
webappService.saveWebapp(webapp);
addWebappToEnvironment(webapp);
saveEnvironment();
logService.log(Log.SUCCESS, "Webapp successfully added to environment");
/*
* Create bootstrap files
*/
if (webapp.getExt() != null)
compileService.createBootstrap(webapp, JavaScriptFramework.EXTJS);
if (webapp.getSenchaTouch() != null)
compileService.createBootstrap(webapp, JavaScriptFramework.SENCHA_TOUCH);
/*
* Add default themes
*/
if (extFolder != null) webapp.getExt().importTheme(webapp);
if (senchaTouchFolder != null) webapp.getSenchaTouch().importTheme(webapp);
return webapp;
}
/*
* Set the path to our webroot folder
*/
@Override
public boolean setWebrootPath(String path) throws IOException {
/*
* Check to make sure path is valid
*/
File webroot = new File(path);
if (!webroot.exists()) {
logService.log(Log.ERROR, "Path not found", path + " is not a valid folder");
return false;
}
/*
* Make sure it's a webroot folder
*/
boolean hasWeblib = false;
for (String folderName : webroot.list()) {
if (folderName.equals("weblib")) hasWeblib = true;
}
if (!hasWeblib) {
logService.log(Log.ERROR, "Invalid webroot folder",
path + " is missing the required webroot folder." + CR + CR +
"Your webroot must contain a folder named 'weblib' which " + CR +
"contains your AdaptrexJS, ExtJS and Sencha Touch folders."
);
return false;
}
/*
* Save our environment
*/
this.env.setWebrootPath(path);
saveEnvironment();
/*
* Make sure weblib contains web library folders
*/
boolean hasAdaptrex = false;
boolean hasExt = false;
File weblib = new File(path + "/weblib");
for (String folderName : weblib.list()) {
if (folderName.startsWith("adaptrex")) hasAdaptrex = true;
if (folderName.startsWith("ext") || folderName.startsWith("sencha")) hasExt = true;
if (hasAdaptrex && hasExt) {
logService.log(Log.SUCCESS, "Webroot Folder Configured");
return true;
}
}
/*
* If we're here... it's not a proper weblib, so add warning
*/
List<String> missing = new ArrayList<String>();
if (!hasAdaptrex) missing.add("AdaptrexJS");
if (!hasExt) missing.add("ExtJS/Sencha Touch");
String missingString = StringUtils.join(missing, " and ");
logService.log(Log.WARNING, "Missing frameworks",
path + " is missing the required" + CR + missingString + " folder" + CR + CR +
"Your new weblib path has been set but you will need to make the" + CR +
"required frameworks available by doing one fo the following: " + CR +
TAB + "- Run \"adaptrex configure environment\" again to specify the correct folder" + CR +
TAB + "- Manually placing the framework folders in the weblib folder" + CR +
TAB + "- Run \"adaptrex install\" to automatically download and install the frameworks."
);
return false;
}
/*
* Set the sencha cmd path
*/
@Override
public boolean setSenchaCmdPath(String path) {
/*
* Check to make sure path is valid
*/
File parent = new File(path);
if (!parent.exists()) {
logService.log(Log.ERROR, "Path not found", path + " is not a valid folder");
return false;
}
if ((new File(path + "/sencha.jar")).exists()) {
this.env.setCmdPath(path);
logService.log(Log.SUCCESS, "Sencha Cmd Folder Configured");
return true;
} else {
logService.log(Log.ERROR, "Invalid Sencha Cmd Folder",
path + " is not a valid Sencha Cmd folder"
);
return false;
}
}
/*
* Save the current environment settings to disk
*/
@Override
public void saveEnvironment() throws IOException {
Environment e = this.env;
File configFile = new File(configPath);
if (!configFile.exists()) configFile.createNewFile();
Ini ini = new Ini();
ini.load(new FileReader(configFile));
Ini.Section settingsSection = ini.get(Environment.SETTINGS);
if (settingsSection == null) settingsSection = ini.add(Environment.SETTINGS);
settingsSection.put(Environment.WEBROOT_PATH, e.getWebrootPath());
settingsSection.put(Environment.SENCHA_CMD_PATH, e.getCmdPath());
Ini.Section weblibSection = ini.get(Environment.WEBAPPS);
if (weblibSection == null) weblibSection = ini.add(Environment.WEBAPPS);
weblibSection.clear();
Map<String,Webapp> webapps = e.getWebapps();
for (String key : webapps.keySet()) {
Webapp webapp = webapps.get(key);
String webappPath = webapp.getFullPath();
if (webappPath.endsWith("/")) webappPath = webappPath.substring(0, webappPath.length()-1);
weblibSection.put(webapp.getName().replace(" ", ".").toLowerCase(), webappPath);
}
ini.store(configFile);
}
/*
* Add a webapp to the environment
*/
private void addWebappToEnvironment(Webapp webapp) {
String path = webapp.getFullPath();
if (webapp.getName() == null) {
logService.log(Log.WARNING, "Webapp missing name",
"The webapp at the following path does not have a name configured:" + CR +
TAB + path + CR +
"To add a name, run a command similar to: " + CR +
TAB + "adaptrex configure webapp -p=" + path + " -sn=\"New Webapp Name\"" +
CR
);
}
env.getWebapps().put(path, webapp);
}
}