package jetbrains.mps.tool.environment;
/*Generated by MPS */
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import org.jetbrains.annotations.NotNull;
import jetbrains.mps.project.Project;
import java.util.Collection;
import jetbrains.mps.library.ModulesMiner;
import jetbrains.mps.make.MPSCompilationResult;
import jetbrains.mps.smodel.ModelAccessHelper;
import jetbrains.mps.util.Computable;
import jetbrains.mps.make.ModuleMaker;
import jetbrains.mps.util.IterableUtil;
import jetbrains.mps.progress.EmptyProgressMonitor;
import java.util.Set;
import org.jetbrains.mps.openapi.module.SModule;
import java.lang.reflect.InvocationTargetException;
import jetbrains.mps.classloading.ClassLoaderManager;
import jetbrains.mps.internal.collections.runtime.SetSequence;
import jetbrains.mps.project.AbstractModule;
public abstract class ProjectStrategyBase implements ProjectStrategy {
private static final Logger LOG = LogManager.getLogger(ProjectStrategyBase.class);
@Override
public boolean isApplicable() {
return true;
}
@NotNull
public Project create(@NotNull Environment env) {
if (isApplicable()) {
Project emptyProject = env.createEmptyProject();
return construct(emptyProject);
}
throw new IllegalStateException("Strategy " + this + " is not applicable -- cannot create project");
}
@NotNull
protected abstract Project construct(@NotNull Project emptyProject);
@NotNull
protected Project loadProjectFromModuleHandles(@NotNull Project emptyProject, Collection<ModulesMiner.ModuleHandle> moduleHandles) {
Project projectFilledWithModules = new ProjectModulesFiller(emptyProject, moduleHandles).load();
return projectFilledWithModules;
}
private static MPSCompilationResult makeAllInCreatedEnvironment(final Project project) {
if (LOG.isInfoEnabled()) {
LOG.info("Building modules within project");
}
return new ModelAccessHelper(project.getModelAccess()).runReadAction(new Computable<MPSCompilationResult>() {
public MPSCompilationResult compute() {
return new ModuleMaker().make(IterableUtil.asCollection(project.getRepository().getModules()), new EmptyProgressMonitor());
}
});
}
@NotNull
protected Project makeOnFirstTimeOpened(@NotNull Project project) {
MPSCompilationResult result = makeAllInCreatedEnvironment(project);
if (!(result.isOk())) {
throw new IllegalStateException("Cannot proceed with compilation errors");
}
try {
Set<SModule> changedModules = result.getChangedModules();
if (result.isReloadingNeeded()) {
reloadAllAfterMake(project, changedModules);
}
updateModelsInModules(project, changedModules);
} catch (Exception e) {
throw new RuntimeException(e);
}
return project;
}
protected static void reloadAllAfterMake(@NotNull Project project, final Set<SModule> changed) throws InterruptedException, InvocationTargetException {
if (LOG.isInfoEnabled()) {
LOG.info("Reloading built modules");
}
// todo create make process listeners, class loading is a client
project.getModelAccess().runWriteAction(new Runnable() {
public void run() {
ClassLoaderManager.getInstance().reloadModules(changed);
}
});
}
/**
* Why do not we need it in IDE?
* Danya:
* added reload of all changed (or new) models after make.
* Usecase: stub model with source at classes_gen dir which is populated only during make.
* But by that time model repository is already filled and it has no such models since there was no class files
* when it got filled.
*/
protected static void updateModelsInModules(@NotNull Project project, final Set<SModule> changed) {
project.getModelAccess().runWriteAction(new Runnable() {
public void run() {
for (SModule module : SetSequence.fromSet(changed)) {
if (module instanceof AbstractModule) {
((AbstractModule) module).updateModelsSet();
}
}
}
});
}
}