/* * Copyright 2003-2015 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.util.ClassType; import jetbrains.mps.classloading.CustomClassLoadingFacet; import jetbrains.mps.java.stub.PackageScopeControl; import jetbrains.mps.library.ModulesMiner; import jetbrains.mps.module.ReloadableModuleBase; import jetbrains.mps.project.facets.TestsFacet; import jetbrains.mps.project.persistence.SolutionDescriptorPersistence; import jetbrains.mps.project.structure.model.ModelRootDescriptor; import jetbrains.mps.project.structure.modules.ModuleDescriptor; import jetbrains.mps.project.structure.modules.SolutionDescriptor; import jetbrains.mps.project.structure.modules.SolutionKind; import jetbrains.mps.reloading.CommonPaths; import jetbrains.mps.smodel.BootstrapLanguages; import jetbrains.mps.util.MacrosFactory; import jetbrains.mps.util.annotation.Hack; import jetbrains.mps.vfs.IFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.persistence.Memento; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * Igor Alshannikov * Aug 26, 2005 */ public class Solution extends ReloadableModuleBase { private SolutionDescriptor mySolutionDescriptor; public static final String SOLUTION_MODELS = "models"; // idea plugin wants to turn it off sometimes, when it knows better what jdk is and what platform is private boolean myUpdateBootstrapSolutions = true; private static Map<SModuleReference, ClassType> bootstrapCP = initBootstrapSolutions(); private static Map<SModuleReference, ClassType> initBootstrapSolutions() { Map<SModuleReference, ClassType> result = new HashMap<SModuleReference, ClassType>(); result.put(BootstrapLanguages.jdkRef(), ClassType.JDK); result.put(BootstrapLanguages.jdkToolsRef(), ClassType.JDK_TOOLS); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("Annotations", ModuleId.fromString("3f233e7f-b8a6-46d2-a57f-795d56775243")), ClassType.ANNOTATIONS); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.OpenAPI", ModuleId.fromString("8865b7a8-5271-43d3-884c-6fd1d9cfdd34")), ClassType.OPENAPI); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Core", ModuleId.fromString("6ed54515-acc8-4d1e-a16c-9fd6cfe951ea")), ClassType.CORE); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Editor", ModuleId.fromString("1ed103c3-3aa6-49b7-9c21-6765ee11f224")), ClassType.EDITOR); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Platform", ModuleId.fromString("742f6602-5a2f-4313-aa6e-ae1cd4ffdc61")), ClassType.PLATFORM); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.IDEA", ModuleId.fromString("498d89d2-c2e9-11e2-ad49-6cf049e62fe5")), ClassType.IDEA); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("MPS.Workbench", ModuleId.fromString("86441d7a-e194-42da-81a5-2161ec62a379")), ClassType.WORKBENCH); result.put(new jetbrains.mps.project.structure.modules.ModuleReference("Testbench", ModuleId.fromString("920eaa0e-ecca-46bc-bee7-4e5c59213dd6")), ClassType.TEST); return result; } /* TODO make package local, move to appropriate package */ public Solution(SolutionDescriptor descriptor, @Nullable IFile file) { super(file); mySolutionDescriptor = descriptor; setModuleReference(descriptor.getModuleReference()); } private static void populateModelRoot(ClassType classType, ModelRootDescriptor javaStubsModelRoot) { PackageScopeControl psc = null; switch (classType) { case JDK: PackageScopeControl jdkPackages = new PackageScopeControl(); jdkPackages.setSkipPrivate(true); jdkPackages.includeWithPrefix("java."); jdkPackages.includeWithPrefix("javax."); jdkPackages.includeWithPrefix("org."); // sun.awt used in mbeddr jdkPackages.includeWithPrefix("sun.awt."); psc = jdkPackages; break; case JDK_TOOLS: psc = new PackageScopeControl(); psc.isSkipPrivate(); psc.includeWithPrefix("com.sun.codemodel."); psc.includeWithPrefix("com.sun.source."); psc.includeWithPrefix("com.sun.tools."); psc.includeWithPrefix("com.sun.jarsigner."); psc.includeWithPrefix("com.sun.javadoc."); psc.includeWithPrefix("com.sun.jdi."); psc.includeWithPrefix("org.relaxng."); psc.includeWithPrefix("sun.jvmstat."); psc.includeWithPrefix("sun.rmi.rmic."); psc.includeWithPrefix("sun.tools."); psc.includeWithPrefix("sun.applet."); break; case PLATFORM: case IDEA: PackageScopeControl platformPackages = new PackageScopeControl(); // mbeddr uses reflection (though custom dsl) to access MPS internals // hence we need to expose private methods unless this reflection language and its uses are removed // platformPackages.setSkipPrivate(true); psc = platformPackages; break; } if (psc != null) { final Memento m = javaStubsModelRoot.getMemento().createChild("PackageScope"); psc.save(m); } } @NotNull @Override public SolutionDescriptor getModuleDescriptor() { return mySolutionDescriptor; } @Override protected void doSetModuleDescriptor(ModuleDescriptor moduleDescriptor) { mySolutionDescriptor = (SolutionDescriptor) moduleDescriptor; SModuleReference mp; if (mySolutionDescriptor.getNamespace() != null) { mp = new jetbrains.mps.project.structure.modules.ModuleReference(mySolutionDescriptor.getNamespace(), mySolutionDescriptor.getId()); } else { assert myDescriptorFile != null; mp = new jetbrains.mps.project.structure.modules.ModuleReference(myDescriptorFile.getPath(), mySolutionDescriptor.getId()); } setModuleReference(mp); } public void setUpdateBootstrapSolutions(boolean b) { myUpdateBootstrapSolutions = b; } @Override public void save() { super.save(); //do not save stub solutions (otherwise build model generation fails) SModuleReference ref = this.getModuleReference(); if (isBootstrapSolution(ref)) return; // in StubSolutions myDescriptorFile is null, so preventing NPE here (MPS-16793) if (myDescriptorFile == null || isReadOnly()) return; if (mySolutionDescriptor.getLoadException() != null){ return; } SolutionDescriptorPersistence.saveSolutionDescriptor(myDescriptorFile, getModuleDescriptor(), MacrosFactory.forModule(this)); } public static boolean isBootstrapSolution(SModuleReference ref) { return bootstrapCP.keySet().contains(ref); } @Override public void updateModelsSet() { if (myUpdateBootstrapSolutions) { updateBootstrapSolutionLibraries(); } super.updateModelsSet(); } @Hack private void updateBootstrapSolutionLibraries() { ModuleDescriptor descriptor = getModuleDescriptor(); ClassType classType = bootstrapCP.get(descriptor.getModuleReference()); if (classType == null) return; // do it only for first time if (descriptor.getModelRootDescriptors().isEmpty()) { for (String path : CommonPaths.getMPSPaths(classType)) { final Collection<ModelRootDescriptor> modelRootDescriptors = descriptor.getModelRootDescriptors(); IFile pathFile = getFileSystem().getFile(path); final ModelRootDescriptor javaStubsModelRoot = ModelRootDescriptor.getJavaStubsModelRoot(pathFile, modelRootDescriptors); if (javaStubsModelRoot != null) { modelRootDescriptors.add(javaStubsModelRoot); populateModelRoot(classType, javaStubsModelRoot); } if (classType.hasOwnJavaStubs()) { descriptor.getAdditionalJavaStubPaths().add(path); } } } } public String toString() { return getModuleName() + " [solution]"; } public SolutionKind getKind() { return getModuleDescriptor().getKind(); } @Override protected void collectMandatoryFacetTypes(Set<String> types) { super.collectMandatoryFacetTypes(types); types.add(TestsFacet.FACET_TYPE); } @Override protected SolutionDescriptor loadDescriptor() { IFile file = getDescriptorFile(); assert file != null; return (SolutionDescriptor) new ModulesMiner().loadModuleHandle(file).getDescriptor(); } @Override public boolean willLoad() { // TODO mps facet from this [like IDEA plugin facet] return getKind() != SolutionKind.NONE || getFacet(CustomClassLoadingFacet.class) != null; } }