package jetbrains.mps.tool.environment;
/*Generated by MPS */
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import jetbrains.mps.library.LibraryInitializer;
import jetbrains.mps.project.PathMacrosProvider;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.RuntimeFlags;
import jetbrains.mps.TestMode;
import java.util.Map;
import java.util.HashMap;
import java.io.File;
import jetbrains.mps.internal.collections.runtime.MapSequence;
import jetbrains.mps.project.PathMacros;
import jetbrains.mps.core.tool.environment.util.MapPathMacrosProvider;
import jetbrains.mps.core.tool.environment.util.CanonicalPath;
import java.util.List;
import jetbrains.mps.library.contributor.LibraryContributor;
import jetbrains.mps.internal.collections.runtime.ListSequence;
import java.util.ArrayList;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import org.jetbrains.annotations.Nullable;
import jetbrains.mps.project.Project;
import jetbrains.mps.InternalFlag;
import java.util.Set;
import jetbrains.mps.util.PathManager;
/**
* Base class for all environments, represents a caching environment.
* The contract: only one environment must be alive,
* it is being stored in the special EnvironmentContainer class.
*
* @see jetbrains.mps.tool.environment.EnvironmentContainer
*/
public abstract class EnvironmentBase implements Environment {
private static final Logger LOG = LogManager.getLogger(EnvironmentBase.class);
private static final String PLUGINS_PATH = "plugin.path";
private boolean myInitialized;
private int myRefCount;
protected final EnvironmentConfig myConfig;
private LibraryInitializer myLibInitializer;
private PathMacrosProvider myMacrosProvider;
private final ProjectContainer myContainer = new ProjectContainer();
public static void initializeLog4j() {
new Log4jInitializer().init();
LogManager.getLogger(EnvironmentBase.class).info("Initializing environment");
}
public EnvironmentBase(@NotNull EnvironmentConfig config) {
if (!(RuntimeFlags.isTestMode())) {
RuntimeFlags.setTestMode(TestMode.USUAL);
}
myConfig = config;
}
protected void init(@NotNull LibraryInitializer libInitializer) {
if (myInitialized) {
throw new IllegalStateException("Double initialization " + this);
}
myLibInitializer = libInitializer;
initMacros();
initLibraries();
EnvironmentContainer.setCurrent(this);
retain();
myInitialized = true;
}
private PathMacrosProvider initMacros() {
Map<String, String> macros = new HashMap<String, String>();
Map<String, File> macrosConfig = myConfig.getMacros();
for (String name : MapSequence.fromMap(macrosConfig).keySet()) {
MapSequence.fromMap(macros).put(name, MapSequence.fromMap(macrosConfig).get(name).getAbsolutePath());
}
myMacrosProvider = createMapMacrosProvider(macros);
PathMacros.getInstance().addMacrosProvider(myMacrosProvider);
return myMacrosProvider;
}
private static MapPathMacrosProvider createMapMacrosProvider(Map<String, String> macros) {
Map<String, String> realMacros = new HashMap<String, String>();
for (String macroName : macros.keySet()) {
String macroValue = MapSequence.fromMap(macros).get(macroName);
CanonicalPath path = new CanonicalPath(macroValue);
if (path.isValidDirectory()) {
realMacros.put(macroName, path.getValue());
}
}
return new MapPathMacrosProvider(realMacros);
}
private List<LibraryContributor> initLibraries() {
if (LOG.isInfoEnabled()) {
LOG.info("Initializing libraries");
}
final List<LibraryContributor> libContribs = ListSequence.fromList(new ArrayList<LibraryContributor>());
LibraryContributorHelper helper = new LibraryContributorHelper(myConfig, rootClassLoader());
if (SetSequence.fromSet(myConfig.getLibs()).isNotEmpty()) {
ListSequence.fromList(libContribs).addElement(helper.createLibContributorForLibs());
}
if (myConfig.getPlugins() != null && SetSequence.fromSet(myConfig.getPlugins()).isNotEmpty()) {
ListSequence.fromList(libContribs).addElement(helper.createLibContributorForPlugins());
}
myLibInitializer.load(libContribs);
return libContribs;
}
/**
* Root class loader:
* 1. As a root class loader for libraries in LibraryInitializer
* 2. As a root class loader for dumb idea plugin facet
*/
@Nullable
protected abstract ClassLoader rootClassLoader();
@Override
public synchronized void retain() {
++myRefCount;
}
@Override
public void release() {
if (myRefCount == 0) {
throw new IllegalStateException("Reference counter is set to zero -- cannot release!");
}
--myRefCount;
if (myRefCount == 0) {
doDispose();
EnvironmentContainer.clear();
}
}
@Override
@NotNull
public Project createProject(@NotNull ProjectStrategy strategy) {
checkInitialized();
return strategy.create(this);
}
/**
* Contract:
* Returns null if there is no opened project with such File
*/
@Nullable
public final Project getOpenedProject(@NotNull File projectFile) {
checkInitialized();
return myContainer.getProject(projectFile);
}
@Override
@NotNull
public Project openProject(@NotNull File projectFile) {
checkInitialized();
Project lastUsedProject = getOpenedProject(projectFile);
if (lastUsedProject != null) {
if (LOG.isInfoEnabled()) {
LOG.info("Using the last created project");
}
return lastUsedProject;
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Opening a new project");
}
Project project = doOpenProject(projectFile);
flushAllEvents();
return project;
}
}
protected abstract void doDispose();
protected abstract Project doOpenProject(@NotNull File projectFile);
@Override
public final synchronized void dispose() {
checkInitialized();
if (LOG.isDebugEnabled()) {
LOG.debug("Disposing environment");
}
myRefCount = 0;
doDispose();
EnvironmentContainer.clear();
}
protected static void setSystemProperties(boolean loadIdeaPlugins) {
System.setProperty("idea.is.internal", InternalFlag.isInternalMode() + "");
System.setProperty("idea.no.jre.check", "true");
System.setProperty("idea.load.plugins", loadIdeaPlugins + "");
}
protected static void setIdeaPluginsToLoad(EnvironmentConfig config) {
if (isEmptyString(System.getProperty(PLUGINS_PATH))) {
// this is always true except when running from ant
setPluginPath();
setIdeaPluginsToLoad0(config);
}
}
private static void setIdeaPluginsToLoad0(EnvironmentConfig config) {
StringBuilder result = new StringBuilder();
Set<PluginDescriptor> plugins = config.getPlugins();
if (plugins == null) {
return;
}
for (PluginDescriptor plugin : SetSequence.fromSet(plugins)) {
result.append(plugin.getId());
result.append(",");
}
System.setProperty("idea.load.plugins.id", result.toString());
}
protected static void setPluginPath() {
StringBuilder pluginPath = new StringBuilder();
File pluginDir = new File(PathManager.getPreInstalledPluginsPath());
if (pluginDir.exists()) {
for (File pluginFolder : pluginDir.listFiles()) {
if (pluginPath.length() > 0) {
pluginPath.append(File.pathSeparator);
}
pluginPath.append(pluginFolder.getPath());
}
System.setProperty(PLUGINS_PATH, pluginPath.toString());
}
}
protected final void checkInitialized() {
if (!(myInitialized)) {
throw new EnvironmentBase.EnvironmentNotInitializedException();
}
}
private static class EnvironmentNotInitializedException extends IllegalStateException {
public EnvironmentNotInitializedException() {
super("#init() method must be called before using an environment");
}
}
private static boolean isEmptyString(String str) {
return str == null || str.length() == 0;
}
}