/* * Copyright 2003-2014 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.project; import jetbrains.mps.smodel.DefaultScope; import jetbrains.mps.smodel.Language; import jetbrains.mps.smodel.MPSModuleOwner; import jetbrains.mps.util.annotation.ToRemove; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.module.ModelAccess; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.module.SRepository; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; /** * MPS Project abstraction. Project may rely on the idea Project or it may not. * It has a scope and a corresponding project repository to store modules in it. */ public abstract class Project implements MPSModuleOwner, IProject { private static final Logger LOG = LogManager.getLogger(Project.class); private final String myName; private final ProjectScope myScope = new ProjectScope(); private final ProjectRepository myRepository; private boolean myDisposed; protected Project(String name) { myName = name; myRepository = new ProjectRepository(this); myRepository.init(); } @NotNull @Override public final ProjectScope getScope() { return myScope; } @Override @NotNull public final SRepository getRepository() { return myRepository; } /** * Shorthand for <code>getRepository().getModelAccess()</code> * * @return access facility to models coming from a {@link #getRepository() repository} associated with this project. */ @Override @NotNull public final ModelAccess getModelAccess() { return myRepository.getModelAccess(); } @NotNull @ToRemove(version = 3.4) public abstract String getName(); @ToRemove(version = 3.3) public abstract <T> T getComponent(Class<T> t); /** * @deprecated the project is not necessarily backed up by file. Left for compatibility * @see FileBasedProject */ @Deprecated @ToRemove(version = 3.3) public File getProjectFile() { if (this instanceof FileBasedProject) { FileBasedProject fileBasedProject = (FileBasedProject) this; return fileBasedProject.getProjectFile(); } return null; } /** * @deprecated use {@link #getProjectModules)} instead * AP fixme : why to return Iterable<? extends>? isn't it easier to give out a collection, e.g. a list? */ @NotNull @Deprecated public final Iterable<? extends SModule> getModules() { return getProjectModules(); } @NotNull public final List<SModule> getProjectModulesWithGenerators() { final ArrayList<SModule> result = new ArrayList<>(); // although getProjectModules likely to access cached value, Language.getGenerators needs MA. // Since we are interested in a consistent repository state, and add/remove of a module from a repository // is guarded by repository's MA, it doesn't hurt to ensure proper access here. getModelAccess().runReadAction(() -> { for (SModule m : getProjectModules()) { result.add(m); if (m instanceof Language) { result.addAll(((Language) m).getGenerators()); } } }); return result; } /** * @deprecated use {@link #getProjectModulesWithGenerators()} instead */ @Deprecated @NotNull public final Iterable<? extends SModule> getModulesWithGenerators() { return getProjectModulesWithGenerators(); } // AP todo remove from Project public final boolean isProjectModule(@NotNull SModule module) { return getProjectModules().contains(module); } // AP todo transfer from Project to ProjectBase; helping method -- no need to be here @NotNull public final <T extends SModule> List<T> getProjectModules(Class<T> moduleClass) { List<T> result = new ArrayList<T>(); for (SModule module : getProjectModules()) { if (moduleClass.isInstance(module)) { result.add(moduleClass.cast(module)); } } return result; } // AP todo transfer from Project to ProjectBase public final Iterable<SModel> getProjectModels() { List<SModel> result = new ArrayList<SModel>(); for (SModule module : getProjectModules()) { for (SModel model : module.getModels()) { result.add(model); } } return result; } @Override public final boolean isHidden() { return false; } @NotNull public String toString() { return "MPS Project [" + myName + "] " + (myDisposed ? ", disposed]" : "]"); } /** * closes and disposes the project */ public void dispose() { myRepository.dispose(); myDisposed = true; } final void checkNotDisposed() { if (isDisposed()) { throw new IllegalStateException("Cannot proceed with disposed project " + this); } } public boolean isDisposed() { return myDisposed; } public final class ProjectScope extends DefaultScope { @Override protected Set<SModule> getInitialModules() { List<Project> openProjects = ProjectManager.getInstance().getOpenedProjects(); assert openProjects.contains(Project.this) : "trying to get scope on a not-yet-loaded project"; Set<SModule> result = new HashSet<SModule>(); result.addAll(getProjectModules(SModule.class)); for (Language l : getProjectModules(Language.class)) { result.addAll(l.getGenerators()); } return result; } } }