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(); } } } }); } }